Lecture 19

Factory Method Pattern

  • Methods in this pattern create objects for us, without having to specify which exact type of object to create

UML

Factory Method Pattern Example:

  • Write a video game with 2 kinds of enemies: turtle and bullets

  • System randomly sends turtle and bullets, but bullets more frequent in harder levels

Example UML:

  • Never know exactly which enemy comes next, so can't call turtle/bullet constructors directly

  • Instead, put a factory method in Level that creates enemies

class Level {
  public:
    virtual Enemy *createEnemy()=0;
};

class Easy: public Level {
  public:
    Enemy *createEnemy() override {
      // easy levels would have higher probability of creating turtles randomly rather than bullets

    }
};

class Hard: public Level {
  public: 
    Enemy *createEnemy() override {
        // harder level would have a higher probability of producing a bullet than turtles
        // might also check game progress and generate boss at certain point
    }
};

Level *l = new Easy/Hard
Enemy *e = l->createEnemy();
// the factory method calls the level function to give the correct probability of getting a turtle or a bullet
// we did not call the constructor for an enemy, but the factory method calls it for us
// we also did not have to decide whether to create a turtle or a bullet, since `createEnemy` decides for us
}

Template Method Pattern

  • design pattern where we override some behaviour from a superclass, but not all of it

    • superclass is used as a template for subclass

  • Template Method:

    • method that outlines an algorithm

    • May have steps of the algorithm call virtual methods (often private) which are implemented in subclass

    • Does most of the work, but subclasses responsible for implementing

  • Want subclasses to override superclass behaviour, but some aspects must stay the same

  • eg. There are red and green turtles

Example:

  • Subclasses can't change the way a turtle is drawn (head, shell, feet), but can change the way the shell is drawn

Generalization: the Non-Virtual Interface (NVI) idiom

Non-Virtual Interface (NVI)

Public Virtual Method

  • A public virtual method is really 2 things:

    1. Interface to the client (public)

      • indicates provided behaviour with pre/post conditions

    2. Interface to subclasses (virtual)

      • a "hook" to insert specialized behaviour

However, these two are conflicting goals.

NVI says:

  1. All public methods should be non-virtual.

  2. All virtual methods should be private (or at least protected)

  3. (Except the destructor)

Example:

Generalizes TemplateMethod

  • puts every virtual method inside a template method

STL Maps - For creating dictionaries

eg. "arrays" that map strings to ints

Important Note: If you call a key that does not exist, the map will create a key with initial value of 0 for ints

Iterating over a map

  • Iterates in sorted key order

    • i.e. does not iterate in order that you added into the map like an array

  • notice p.first and p.second are FIELDS, not METHODS

  • pair is a template structure, and the fields are actually PUBLIC

    • Why is this ok?

      • Because pair is not an abstraction and there is no invariance - you WANT to manipulate the keys (the struct only acts like glues, there are no rules)

Visitor Pattern

  • For implementing double dispatch

Double Dispatch: Dispatching methods based on type of multiple objects, also used for adding extra functionality to class hierarchy without changing any of the classes in the hierarchy

  • Virtual methods in Visitor Pattern are chosen based on the actual type (at runtime) of the receiving object

  • What if you want to choose based on two objects? eg. striking enemies with weapon

UML

  • Want something like virtual void (Enemy, Weapon)::strike(); If strike is a method of Enemy - choose based on enemy, but on a weapon If strike is a method of Weapon - choose based on weapon but not on enemy

The trick is to get dispatch on both (double dispatch)

  • combines overriding and overloading

**Bullet::beStruckBy runs (virtual method)

  • calls Weapon::strike, *this is a bullet

    • Bullet version of strike is chosen at compile-time

    • virtual method strike on Weapon resolves to Stick::strike(Bullet &b)

Last updated

Was this helpful?