Search This Blog

Monday, October 26, 2009

Design Patterns, Overview

OpenClose principle:
Base class defines the interface. Client can use them, code never break;
Sub class extends the interface. The functionality is extended, and interface remains the same.

1. private static self instance
2. private constructor, assignment operator, copy constructor
3. static get_instance() call
worry about initial setting of the self_instance (static null at first?), when to delete the self instance, and the multi-thread environment. (because the order of initializing static variable is hard to predict) p.171, Item 35 effective C++

Extend functionality. 1.taking a base class object in the constructor. 2. redefine the the interface using the base's class method.

1. taking a base class object in the constructor. 2. convert the base class interface by wrapping the base class method in a new method.

Treat a class as function object (callback).
In C++, you can create/grab a function object that is ready to be consumed. You know "when" to consume the event(the function object) by calling operator() on the event/comment/function object, and the command object knows "what" to do. Thus, decoupling is present.

Another way to implement command pattern: a base command class has execute() method, the command subclass overwrite the execute() method.
1. Different from the original function pointer, a function object has "state". Therefore, we can easily add an undo() command, which can restore the previous state we have saved before calling execute()
2. We can also set up a command vector, so we can "undo" several times (back to the previous vector command and execute them)

Template Method: NVI, nonvirtual interface idiom
the client uses the the base's class public method (wrapper), to call the base class private virtual function redefined in the client class. (overwrite certain steps). The subclass redefine the private virtual function they can't call! But the client knows how to call, the base class knows when to call!

Each state subclass overwrites the functions in the base class, base on each "state subclass". On the client side, we can swap different state class as our "current state", and we just call the original functions define in the base class. The appropriate function for each state will be called, since they are virtual.
how to implement:
1. define as many states as you want, each state overwrites the base class interface as needed
2. initialize all the state classes in the constructor.
3. in each state class, you need a method like "change state" so the client class knows which state class to use.

Swap the behavior class at run time by taking the strategy class in the constructor. This strategy class can be just a member inside another class.

Chain of Responsibility:
Using a list of handling methods. 1. store the method in a chain of vector 2. or using vertical chain, meaning calling the base class handler (method) or switch the handler to other object.

1. observers can attach() a subject, and subject will add the observer to subject's list inside attach
2. subject calls notify. inside notify the subject calls each observer's update() and using subject's state as the argument for the update.

Factory: (object creation)
Help you to create type through a factory class. You can add new type later without modifying the factory class. Your abstract factory, for example, has a interface call MakeCar(), return a new car type. (abstract factory contains a family of related types, makeCar, makeWheel, etc) Later on, you can add a new Toyota car (subclassing car type), and your new concret toyota factor overwrite the MakeCar(), returning a Toyota car. Notice we still use the base class MakeCar() method, which generating a car to us, with a new car type we just added (and we can create this new type), without changing the base class MakeCar interface at all.

Factory patten is also very helpful on eliminating type checking when making a new object. For example, a flower base class can generate a pricing modle (class) by saying flower.getPricingModel(). Since the pricing model depends on the actual type of flower, you are tempting to use dynamic_cast to check the actual flower type. This is not necessary with the factory pattern. Just in every subclass of flower, overwrite the base's getPricingModel() method, return the particular model class for that particular type of flower.

Double Dispatching:
First dispatch: a is a subclass, dostuff is a virtual function. It result in the 1st dispatch.
Second dispatch: inside dostuff(), another call is b->makeTea(). b is a subclass, makeTea is a virtual function. It results in the 2nd dispatch.
The sequence can go longer, not restricting to double dispatching. It is a pattern used in Visitor Pattern (not really useful though)

No comments: