Design Patterns notes (on)

Design Patterns notes (on)

Personal notes to learn design patterns. The main reference "Head First Design Patterns" and Wikipedia, there are on youtube a video series is also well worth a look

chap 1 entry Design Patterns - Strategy Pattern

definition

Strategy Pattern Strategy Pattern defines the algorithm clusters were encapsulated, so that they can replace each other, this mode lets the algorithm vary independently from clients using the algorithm.

analysis

  • Environment (Context): holds a reference to a Strategy
  • Abstract Strategy (Strategy): This is an abstract role, usually implemented by an interface or abstract class. This role gives specific strategies required for all class interface
  • Specific strategies (ConcreteStrategy): packaging related algorithms or behavior

Using subclass inherits behavior design, are statically determined at compile time, but the same inherited behavior; the use of Scalable objects Behavior in combination, can be extended dynamically at runtime.

It has inherited behavior patterns policy portfolio composition + = delegate delegation, to achieve operation

UML

https://en.wikipedia.org/wiki/Strategy_pattern

Code

Duck code below can also be designed as a base class, simplified here for simplicity.

#include <iostream>
#include <memory>

// strategy
class FlyBehavior {
public:
    typedef std::shared_ptr<FlyBehavior> Ptr;
    virtual void fly()=0;
    virtual ~FlyBehavior(){};
};

// concrete strategy
class FlyWithWings:public FlyBehavior{
public:
    void fly() override {
        std::cout<<"I am flying\n";
    }
};

class FlyNoWay:public FlyBehavior{
public:
    void fly() override {
        std::cout<<"I can't fly\n";
    }
};

// context
class Duck{
public:
    Duck(const FlyBehavior::Ptr &flyBehavior) : flyBehavior_(flyBehavior) {}
    void performFly(){flyBehavior_->fly();}
private:
    FlyBehavior::Ptr flyBehavior_;
};

// test
int main(){
    FlyBehavior::Ptr flyBehavior(new FlyNoWay);
    Duck duck(flyBehavior);
    duck.performFly();

    return 0;
}

other

Design Principles

  • Find applications may require changes in place, put them independent, and do not need to change the code of those mixed
  • For interface programming, rather than programming
  • Multi-purpose combination, less inheritance

Mode is a common solution for the design problem, most models allow partial change independent of the rest.

chap2 make you aware of the status of the object - the observer mode

definition

Observer Pattern mode observer defines many dependency between objects, so that, when an object changes state, all of its dependents will be notified and updated automatically.

analysis

  • Theme (Subject): generally interface or class, store a reference to all of the observer. Use a common interface to update the viewer. Called talker, publisher may be more appropriate;
  • Observers (Observer): set to the interface, each entity viewer interface function needs to be rewritten. Called listener, subscriber may be more appropriate;
  • Specific observer (Concrete Observer): implement the Observer interface.

Between the observer and the theme is loosely coupled: Topic not know the details of the observer, the observer knows only achieve observer interface.

, When the publisher can get data from by pushing push or pull the pull to get data mode, push seems to be more common.

When there are a plurality of subscriber, you can not rely on specific notification sequence.

Many often use GUI framework observer mode, listen for events such as Android in the control function. Here nature is to use the callback mechanism to achieve: the publisher trigger some kind of event, call the callback function; subscriber achieve the appropriate custom function in the callback function. When calling the callback function, the parameters can be passed, the parameters can also be empty.

UML

https://en.wikipedia.org/wiki/Observer_pattern

Code

#include <iostream>
#include <memory>
#include <vector>

// observer
class Observer {
public:
    typedef std::shared_ptr<Observer> Ptr;
    virtual void update(std::string event)=0;
    virtual ~Observer(){};
};

// concrete observer
class ObserverOne:public Observer{
public:
    void update(std::string event) override {
        std::cout<<"Observer One received response: "+event<<std::endl;
    }
};

class ObserverTwo:public Observer{
public:
    void update(std::string event) override {
        std::cout<<"Observer Two received response: "+event<<std::endl;
    }
};

// subject
class EventSource {
public:
    void addObserver(const Observer::Ptr& observer){observers_.push_back(observer);}
    void scanInput(){
        std::string input;
        while (std::getline(std::cin,input)){
            notifyObserver(input);
        }
    }
private:
    void notifyObserver(std::string event){
        for(auto item:observers_)
            item->update(event);
    }

    std::vector<Observer::Ptr> observers_;
};

// test
int main(){
    Observer::Ptr observer1(new ObserverOne);
    Observer::Ptr observer2(new ObserverTwo);

    EventSource eventSource;
    eventSource.addObserver(observer1);
    eventSource.addObserver(observer2);
    eventSource.scanInput();

    return 0;
}

other

Design Principles

  • To loosely coupled interaction between design objects and work

Tip: by setChanged()method of labeling the state has changed, and then inform the viewer, so that is more flexible and can control the timing of the notification, such as notification can be used to avoid frequent observer.

chap3 decorative objects - decorator pattern

definition

Decorator Pattern Decorator Pattern dynamically responsibility attached to an object, to have extensions, decorated to provide a more flexible than inheritance alternative.

analysis

  • Decorator (Decorator): inherited from the component class that contains the component references in order to achieve the purpose of packaging wrap, by this reference method before decorative component object can call (ie forward forward), and override some methods need to modify the requirements in order to achieve decorative the goal of
  • Component (Component): is an abstract class, the common parent class is abstract and concrete decorative member of

Because decorator must be able to replace the decorator (components), therefore inherited the role here is to achieve the "Type Mismatch", instead of using inheritance to get "behavior." Decorator and behavior from the basic components, or a combination of the relationship between the other decorators.

Many Java I / O-related class decorator pattern is used, such as FilterInputStream and so on. Many decorators can use a packaging component, but it will also result in the emergence of many small objects, the program structure is complicated.

UML

https://en.wikipedia.org/wiki/Decorator_pattern

Code

#include <iostream>
#include <string>

// abstract component (decorator)
class Beverage{
public:
    virtual double cost()=0;
    virtual ~Beverage() {}
};

// concrete component
class Espresso:public Beverage{
public:
    double cost() override {
        return 1.99;
    }
};

// concrete decorator
class Mocha:public Beverage{
public:
    Mocha(Beverage *beverage) : beverage_(beverage) {}

    double cost() override {
        return beverage_->cost()+.20;
    }

private:
    Beverage* beverage_;
};

int main() {
    Espresso coffee;
    std::cout<<"original coffee: "<<coffee.cost()<<std::endl;

    Beverage* coffee_with_mocha=new Mocha(&coffee);
    coffee_with_mocha=new Mocha(coffee_with_mocha);
    std::cout<<"coffee with double mocha: "<<coffee_with_mocha->cost()<<std::endl;

    return 0;
}

other

Design Principles

  • Open for extension, closed for modification

Forwarding forward with the commission delegation comparing the two are similar, but there are differences:

  • Forwarded

Here is an example in Java, from Wikipedia. Printer includes a print method, but this method does not own a specific implementation, but forward to the responsibility of an object RealPrinter. From the outside, as if Printer output string, but actually RealPrinter do the actual work.

Plan Key: Forward pot that is training and preparation of others

应用:Chain-of-responsibility pattern、Decorator pattern、Proxy pattern等

class RealPrinter { // the "receiver" (wrappee)
    void print() { 
        System.out.println("Hello world!"); 
    }
 }

 class Printer {    // the "sender" (wrapper)
    RealPrinter p = new RealPrinter();  // create the receiver
    void print() {
        p.print(); // calls the receiver
    }
 }
  
 public class Main {
    public static void main(String[] arguments) {
                // to the outside world it looks like Printer actually prints.
        Printer printer = new Printer();
        printer.print();
    }
 }
  • Entrust

And commissioned more like forward, but there are some differences. Delegate, self refer to sender, and forwarding, self refer to the receiver. Or, according to one of the SO answer , a special commission be forwarded, but forwarded to the interface itself , which is the strategy pattern in practice.

chap 4 baking loosely coupled OO design - factory pattern

The book is divided into three kinds , i.e., a simple factory pattern, factory method and abstract factory pattern mode.

Please reference this section UML

Simple factory pattern

Simple factory pattern does not really regarded as a design pattern, more often is a programming habits.

definition

Definition of a factory class, according to the different return parameters passed in different instances, the instance is created having a common parent class or interface.

analysis

The responsibility single principle object creates separate out a class of work to do, i.e. factory class of this class, the class factory to create all of the work done in one place process.

Code

#include <iostream>
#include <memory>

// product
class Shape{
public:
    typedef std::shared_ptr<Shape> Ptr;
    virtual void draw()=0;
    virtual ~Shape() {}
};

// concrete product
class Circle:public Shape{
public:
    void draw() override {
        std::cout<<"draw: circle\n";
    }
};

class Rectangle:public Shape{
public:
    void draw() override {
        std::cout<<"draw: rectangle\n";
    }
};

// concrete factory
class ShapeFactory{
public:
    Shape::Ptr createShape(std::string type){
        Shape::Ptr shape;
        if (type=="circle")
            shape=Shape::Ptr(new Circle);
        else if (type=="rect")
            shape=Shape::Ptr(new Rectangle);

        return shape;
    }
};

// test
int main(){
    ShapeFactory shapeFactory;
    Shape::Ptr circle=shapeFactory.createShape("circle");
    circle->draw();
    Shape::Ptr rect=shapeFactory.createShape("rect");
    rect->draw();

    return 0;
}

Factory Method pattern

Commonly referred to as factory mode refers to this model, the factory method pattern is most frequently used in daily development of a design pattern.

definition

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory method to instantiate a class model allows to delay its subclasses.

analysis

Factory method model, known as polymorphic factory mode. From the name, you can see its characteristics. Only a simple factory uniform factory class, all in one place to create work are finished processing; and there are many factories factory method class, these factories have achieved a factory class base class. Each subclass looks like a factory as a simple factory.

Code

The following code, each corresponding to a class factory to create a product, corresponding to a plurality of product to be created (in this case may need to pass parameters when constructing the like, as simple as the factory mode). Note the following comparison of the code and factory code simple.

#include <iostream>
#include <memory>

// product
class Shape{
public:
    typedef std::shared_ptr<Shape> Ptr;
    virtual void draw()=0;
    virtual ~Shape() {}
};

// concrete product
class Circle:public Shape{
public:
    void draw() override {
        std::cout<<"draw: circle\n";
    }
};

class Rectangle:public Shape{
public:
    void draw() override {
        std::cout<<"draw: rectangle\n";
    }
};

// factory
class Factory{
public:
    typedef std::shared_ptr<Factory> Ptr;
    virtual Shape::Ptr createShape()=0;
    virtual ~Factory() {}
};

// concrete factory
class CircleFactory:public Factory{
public:
    Shape::Ptr createShape() override {
        return Shape::Ptr(new Circle);
    }
};

class RectFactory:public Factory{
public:
    Shape::Ptr createShape() override {
        return Shape::Ptr(new Rectangle);
    }
};

// test
int main(){
    Factory::Ptr factory(new CircleFactory);
    Shape::Ptr circle=factory->createShape();
    circle->draw();

    Factory::Ptr factory2(new RectFactory);
    Shape::Ptr rect=factory2->createShape();
    rect->draw();

    return 0;
}

Abstract factory pattern

definition

It provides an interface for creating related or dependent objects of the family , without the need to explicitly specify a specific class. (In the abstract factory mode, each specific facility provides a plurality of factory methods for producing a plurality of different types of objects)

analysis

Effect: the target with a series of bundled production , such as the following example code.

Character:

  • AbstractFactory (Abstract Factory) : declare a set of methods for creating an object, note that a set of objects, and this is a set of objects with the match of;
  • ConcreteFactory (plant-specific) : it implements a method to create the object in the declaration of the abstract factory, generates a set of specific objects;
  • AbstractProduct (abstract product) : it is, in the method of the object which declares traffic has interfaces for each object declaration;
  • ConcreteProduct (product-specific) : It defines the specific target specific factory production.

Abstract Factory each method actually look like a factory method: Each method is declared as abstract, while the factory method subclasses override these methods to create certain objects.

Each factory method can only create "a product" and the abstract factory to create "a family of products."

However, the model does not comply with the principle of opening and closing, if you add a new product must change the interface.

Code

Abstract factory pattern with good at producing a series of bundled objects, such as the following examples. If in the production of UI controls, the Android Text-style controls and IOS-style Button control mixed together, it will be very bad. The abstract factory pattern, you can see that you can create related or dependent objects of the family , thus avoiding the production together do not take objects. This section youtube video of the series said very clearly, can refer to.

#include <iostream>
#include <memory>

// product
// some ui widgets
class Text{
public:
    typedef std::shared_ptr<Text> Ptr;
    virtual void showText()=0;
    virtual ~Text() {}
};

class Button{
public:
    typedef std::shared_ptr<Button> Ptr;
    virtual void showButton()=0;
    virtual ~Button() {}
};

// concrete product
// different styled ui widgets
class TextAndroid:public Text{
public:
    void showText() override {
        std::cout<<"Text in Android\n";
    }
};

class TextIOS:public Text{
public:
    void showText() override {
        std::cout<<"Text in IOS\n";
    }
};

class ButtonAndroid:public Button{
public:
    void showButton() override {
        std::cout<<"Button in Android\n";
    }
};

class ButtonIOS:public Button{
public:
    void showButton() override {
        std::cout<<"Button in IOS\n";
    }
};

// factory
class UIFactory{
public:
    typedef std::shared_ptr<UIFactory> Ptr;
    virtual Text::Ptr createText()=0;
    virtual Button::Ptr createButton()=0;
    virtual ~UIFactory() {}
};

// concrete factory
// this are two versions of ui factory for two different platforms
class AndroidUIFactory:public UIFactory{
public:
    Text::Ptr createText() override {
        return Text::Ptr(new TextAndroid);
    }

    Button::Ptr createButton() override {
        return Button::Ptr(new ButtonAndroid);
    }
};

class IOSUIFactory:public UIFactory{
public:
    Text::Ptr createText() override {
        return Text::Ptr(new TextIOS);
    }

    Button::Ptr createButton() override {
        return Button::Ptr(new ButtonIOS);
    }
};

// test
// suppose I now want to create an Android app
int main(){
    UIFactory::Ptr uiFactory(new AndroidUIFactory);
    Text::Ptr text=uiFactory->createText();
    Button::Ptr button=uiFactory->createButton();
    text->showText();
    button->showButton();

    return 0;
}

chap5 unique object - Singleton

definition

Singleton Singleton Pattrn ensure that only one instance of a class, and provide a global access point.

analysis

A static variable, a private constructor, a static method (getInstance ()).

If we consider a multi-threaded, it must make some changes, or it may enter multiple threads at the same time global access point, thereby creating multiple objects. Java, improved in three ways:

  • Synchronization getInstance () method. The disadvantage is low efficiency;
  • Villains mode;
  • double-checked. First check whether the instance is created, if not already created, only to be synchronized.

UML

https://en.wikipedia.org/wiki/Singleton_pattern

Package chap6 call - command mode

definition

Command Mode Command Pattern "request" encapsulated in objects, in order to use different requests, queue or log parameterized other objects. Command mode also supports undo operations.

analysis

  • Command Command: specific command class abstract interface;
  • Specific commands Concrete Command: Packing calculation block (a receiver and a set of action);
  • Receiver Receiver: responsible for invoking the command object to execute the request;
  • Requester Invoker: invoke a command in the form of commission.

A command object (ConcreteCommand) by a particular recipient bindings on a set of actions to package a request. That object will command a set of actions and a receiver packed into an object, the object exposes only execute () method, when this method is called, the receiver will perform these operations. After this packaged objects like normal objects, it can be stored, transferred and call .

The caller acceptable as a command object parameter, even dynamically at runtime.

Command supports withdrawal , approach is to implement an undo () method to return to execute () method of the state before the execution.

Macro command is a simple command extension allows calling a plurality of commands . Also support withdrawn.

Command mode can be used to implement the thread pool, and queues the work requests, and logs.

UML

https://en.wikipedia.org/wiki/Command_pattern

Code

#include <iostream>
#include <memory>

// receiver
class Light{
public:
    typedef std::shared_ptr<Light> Ptr;
    void on(){std::cout<<"Light is on\n";}
    void off(){std::cout<<"Light is off\n";}
};

// command
class Command{
public:
    typedef std::shared_ptr<Command> Ptr;
    virtual void execute()=0;
    virtual ~Command() {}
};

// concrete command
class LightOnCommand:public Command{
public:
    LightOnCommand(const Light::Ptr &light) : light_(light) {}

    void execute() override {
        light_->on();
    }

private:
    Light::Ptr light_;
};

// invoker
class Remote{
public:
    Remote() {}
    void setCommand(Command::Ptr command){command_=command;}
    void onButtonWasPressed(){command_->execute();}

private:
    Command::Ptr command_;
};

// test
int main(){
    Light::Ptr light(new Light);
    Command::Ptr lightOn(new LightOnCommand(light));

    Remote remote;
    remote.setCommand(lightOn);
    remote.onButtonWasPressed();

    return 0;
}

Personal understanding wrong place also please let us know, reproduced, please indicate the source

Guess you like

Origin www.cnblogs.com/GJGJH/p/11073238.html