Friday 2 May 2014

Design Patterns

(This Post is mostly copy from: http://www.sourcetricks.com/2008/06/about-design-patterns.html)

1: Definition

Design patterns can be considered as a standardization of commonly agreed best practices to solve specific design problems.

2: Classification
Depending on the design problem they address, design patterns can be classified in different categories, of which the main categories are:

///////////////////////////////
3. Creational Patterns
///////////////////////////////

creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation.

3.1: Singleton
(全局唯一对象)
  • Singleton is a creational design pattern.
  • A design pattern to provide one and only instance of an object.
  • Make the constructors of the class private.
  • Store the object created privately.
  • Provide access to get the instance through a public method.
  • Can be extended to create a pool of objects. 
C++ Code:
---------------------- 
Class Singleton {
private:
static Singleton* instance;

private:
Singleton()
{}

public:
Singleton* GetInstance();
};
---------------------- 

3.2: Factory Pattern
(中央控制,屏蔽复杂的多态类创建细节)






  • Factory pattern is a creational design pattern.
  • Idea of the factory patterns is to localize the object creation code.
  • This prevents disturbing the entire system for a new type introduction.
  • Typically when a new type is introduced in the system, change is at one place only where the object is created to decide which constructor to use.
  • Simplest of the factory is introduction of a static method in the base class itself, which creates the required object based on the type.

  • Some Good Comments:
    -----------
    • The factory pattern is useful if you need to encapsulate create-time polymorphism from consumers, that is, you want to provide a transparent point from which new instances of a polymorphic type are created.
    • If the type in question is not polymorphic, the factory pattern is pointless.
    • If a single point of creation doesn't make sense, neither does the factory pattern.
    • If it is undesirable to hide the polymorphism details away, the factory pattern is probably inappropriate, too.
    • As with anything that adds complexity, you should default to not using it, but spot the point at which it is beneficial early on and apply it before it is too late.
    ---------

    C++ Code:
    ----------------------
    class Shape {
    public:
      virtual void Draw() = 0;
      static Shape* Create(string type);
    };


    class Circle: public Shape {
    public:
      void Draw() {
        printf("I am a circle\n");
      }
      friend class Shape;
    };


    Shape* Shape::Create(string type) {
      if(type.compare("Circle")) return new Circle();
      return NULL;
    }

    ----------------- 

    Another version is named "Abstract Factory", to move the functions to a separate class.
    Explain:
    Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
    ---------------

    // Abstract Factory returning a mobile
    class MobileFactory {
        public:
           Mobile* GetMobile(string type);
    };
    
    Mobile* MobileFactory::GetMobile(string type) {
        if ( type == "Low-End" ) return new LowEndMobile();
        if ( type == "High-End" ) return new HighEndMobile();
        return NULL;
    }
    ------------------- 

















    3.3: object pool pattern
    (对costly资源的包装和分配)

    The object pool pattern is a software creational design pattern that uses a set of initialized objects kept ready to use – a "pool" – rather than allocating and destroying them on demand. A client of the pool will request an object from the pool and perform operations on the returned object. When the client has finished, it returns the object to the pool rather than destroying it; this can be done manually or automatically.

    Avoid expensive acquisition and release of resources by recycling objects that are no longer in use. Can be considered a generalisation of connection pool (database and networking) and thread pool patterns.

    Object pools employ one of three strategies to handle a request when there are no spare objects in the pool.
    1. Fail to provide an object (and return an error to the client).
    2. Allocate a new object, thus increasing the size of the pool.
    3. In a multithreaded environment, a pool may block the client until another thread returns an object to the pool.
    3.4: Build Pattern
    (对复杂Object的多态包装)
    Separate the construction of a complex object from its representation, allowing the same construction process to create various representations.

    Build Class:
    Define the virtual functions to be overlapped by sub-classes.
    Build Class replaces the role of Product in Director.

    ///////////////////////////////
    4. Structural patterns 
    ///////////////////////////////

    4.1: Adapter Pattern (Wrapper Pattern)
    (接口转换器)

    An adapter helps two incompatible interfaces to work together. This is the real world definition for an adapter. The adapter design pattern is used when you want two different classes with incompatible interfaces to work together. Interfaces may be incompatible but the inner functionality should suit the need. The Adapter pattern allows otherwise incompatible classes to work together by converting the interface of one class into an interface expected by the clients.



  • The adapter translates calls to its interface into calls to the original interface.
  • The adapter is also responsible for transforming data into appropriate forms.
  • The adapter is created by implementing or inheriting both the interface that is expected and the interface that is pre-existing.  






  • C++ Code
    ------------------------
    Class Adapter : public PublicInterface {
    private:
    serviceObject* object;

    public:
    Adapter(serviceObject* object) {this->object = object;}

    public:
    void PublicInterfaceFunction(AAA){
     BBB = transform(AAA);
     object->SomeOtherFunction(BBB)
    }
    };
    ------------------------

    4.2: Composite Pattern
    (对象的树形结构)

    Composite pattern is useful when you want to treat a group of objects in the same manner as a single instance of the object. The objects grouped, themselves could be in composite manner in a tree fashion.















    Compose objects into tree structures to represent leaf-composite hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

    There are two types of components:
    1) working components: Leaf
    2) composite components: a group of components


    4.3: Decorator Pattern 
    (功能增强)

    Useful, when you want to add capabilities (statically or dynamically) to an object without sub-classing the concrete object's class as well as not affecting other objects of the same concrete class.



















    The key is that the Decorate Class extends the functions of the Component but does not sub-class it. (Has-A replaces Is-A)


    4.4: Facade Pattern
    (统一用户接口,提供Module Level Interface)

    • Facade pattern is a structural design pattern.
    • Makes an existing complex software library easier to use by providing a simpler interface for common tasks.
    • Allows the applications/ clients using the library de-coupled from inner workings of a complex library.
















    ///////////////////////////////
    5. Behavioral patterns
    ///////////////////////////////

    5.1: Template Algorithm (or Method) Design Pattern
    (抽象算法-伪代码)

    Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

    • Template pattern is a behavioral design pattern.
    • This has nothing to do with C++ templates as such.
    • Template patterns is a common form in object oriented programming. Having an abstract base class (one or more pure virtual functions) is a simple example of template design pattern.
    • In the template pattern, parts of program which are well defined like an algorithm are defined as a concrete method in the base class. The specifics of implementation are left to the derived classes by making these methods as abstract in the base class.
    • The method which implements the algorithm is also refered as template method and the class which implements this methods as the template class.


    C++ Example: 
    ----------------------------
    // Base class
    // Template class
    class Account {
        public:
            // Abstract Methods
            virtual void Start() = 0;
            virtual void Do() = 0;
            virtual void End() = 0;
    
            // Template Method
            void Withdraw(int amount) {
                Start();
                Do();
                End();  
            }
    };
    ---------------------------- 


    5.2: Chain of Responsibility
    (火枪N联机)


    • Chain of Responsibility is a behavioral design pattern.
    • The basic idea behind this pattern is that a request or a command passes through a chain of objects until it is handled.
    • Objects involved in this pattern are of two types. Processing Objects and Command Objects.
    • Processing objects handle the commands given by command objects.
    • Each processing object knows what it can handle and passes the command to the next member in the chain if not handled.
    • A common example to understand this pattern better is the C++ exception handling mechanism. Unhandled exceptions are passed up the call stack until somebody acts upon it.

    C++ code:
    ---------------------------- 
    
    
    class ErrorHandle {
    
      protected:
        ErrorStates state;
        ErrorHandle* successor;
          
      public: 
        //This handle is only responsible for an error state 
        ErrorHandle(ErrorStates aState) { state = aState; }
    
        void SetSuccessor  (ErrorHandle* handle) {
            this->successor = handle;
        } 
        //if cannot handle, then pass to the next.
        //It is multiple functional calls in the stack. 
        virtual void ProcessError(ErrorReport& report) = 0;
    };
    ----------------------------  

    5.3: Command Pattern
    (用户命令的封装和历史保存)

    Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

    • Command pattern is a behavioral design pattern.
    • Encapsulates a command/ request. The command itself is treated as an object.
    • Classes participating in a command pattern include:-
      • Command:- An abstract interface defining the execute method.
      • Concrete Commands:- Extend the Command interface and implements the execute method. Invokes the command on the receiver object.
      • Receiver:- Knows how to perform the command action.
      • Invoker:- Asks the command object to carry out the request.
      • Client:- Creates the commands and associates with the receiver.
    • Some examples:- 
      • Used when history of requests is needed. (Stock orders executed for today)
      • Asynchronous processing. Commands need to be executed at variant times.
      • Installation wizards.


    Example C++ code:
    --------------

    // Command interface
    class Command
    {
    public:
        virtual void execute() = 0;
    };
    
    // Receiver
    class StockTrade
    {
    public:
        StockTrade() {}
        void buy() { cout << "Buy stock" << endl; }
        void sell() { cout << "Sell stock" << endl; }
    };
    
    // Concrete command 1
    class BuyOrder : public Command
    {
        StockTrade* stock;
    public:
        BuyOrder(StockTrade* stock)
        {
            this->stock = stock;
        }
    
        void execute()
        {
            stock->buy();
        }
    };
    
    // Concrete command 2
    class SellOrder : public Command
    {
        StockTrade* stock;
    public:
        SellOrder(StockTrade* stock)
        {
            this->stock = stock;
        }
    
        void execute()
        {
            stock->sell();
        }
    };
    
    // Invoker
    class StockAgent
    {
    public:
        StockAgent() {}
        void order( Command* command )
        {
            commandList.push_back(command);
            command->execute();
        }
    private:
        // Looking at this command list gives
        // this order history
        vector<Command*> commandList;
    };
    --------------------------- 


    5.4: Visitor Pattern 
    (数据结构与算法分离)

    the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. It is one way to follow the open/closed principle.

    • The visitor pattern is a behavioral design pattern. 
    • Visitor pattern allows to separate the data structures and the algorithms to be applied on the data.
    • Both data structure objects and algorithm objects can evolve separately. Makes development and changes easier.
    • Data structure (element) objects have an "accept" method which take in a visitor (algorithmic) object.
    • Algorithmic objects have a "visit" method which take in a data structure object.

    Example C++ Code
    ----------------------

    // Forwards
    class VisitorIntf;
    
    // Abstract interface for Element objects
    class ElementIntf
    {
    public:
        virtual string name() = 0;
        virtual void accept(VisitorIntf* object) = 0;
    };
    
    // Abstract interface for Visitor objects
    class VisitorIntf
    {
    public:
        virtual void visit(ElementIntf* object) = 0;
    };
    
    // Concrete element object
    class ConcreteElement1 : public ElementIntf
    {
    public:
        string name()
        {
            return "ConcreteElement1";
        }
    
        void accept(VisitorIntf *object)
        {
            object->visit(this);
        }
    };
    
    // Concrete element object
    class ConcreteElement2 : public ElementIntf
    {
    public:
        string name()
        {
            return "ConcreteElement2";
        }
    
        void accept(VisitorIntf *object)
        {
            object->visit(this);
        }
    };
    
    // Visitor logic 1
    class ConcreteVisitor1 : public VisitorIntf
    {
    public:
        void visit(ElementIntf *object)
        {
            cout << "Visited " << object->name() <<
                    " using ConcreteVisitor1." << endl;
        }
    };
    
    // Visitor logic 2
    class ConcreteVisitor2 : public VisitorIntf
    {
    public:
        void visit(ElementIntf *object)
        {
            cout << "Visited " << object->name() <<
                 " using ConcreteVisitor2." << endl;
        }
    };
    ---------------------- 


    5.5: Strategy pattern
    (算法切换)

    In computer programming, the strategy pattern (also known as the policy pattern) is a software design pattern that enables an algorithm's behavior to be selected at runtime. The strategy pattern
    • defines a family of algorithms,
    • encapsulates each algorithm, and
    • makes the algorithms interchangeable within that family.
    It is a straightforward design, so not detailed here.











    ///////////////////////////////
    6. System Design Patterns
    ///////////////////////////////

    6.0: SOLID (object-oriented design)
    (设计圣经I)

    It is part of an overall strategy of agile and adaptive programming.

    1) S: Single responsibility principle
        a class should have only a single responsibility and that responsibility should be entirely encapsulated by the class.
    2) O: Open/closed principle
        software entities … should be open for extension, but closed for modification.
    3) L: Liskov substitution principle
        objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program
    4) I: Interface segregation principle
        many client-specific interfaces are better than one general-purpose interface.
    5) D: Dependency inversion principle
        one should “Depend upon Abstractions. Do not depend upon concretions.”

    6.0: KISS principle
    (设计圣经II)

    Keep it simple, stupid.

    6.1:Publish–subscribe Pattern
    (互不关心的消息分类传递)

    publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers. Instead, published messages are characterized into classes, without knowledge of what, if any, subscribers there may be.

    Similarly, subscribers express interest in one or more classes, and only receive messages that are of interest, without knowledge of what, if any, publishers there are.

    Benefits:
    Loose coupling
    Scalable 

    Disadvantages:
    No guarantee for delivery

    Possible delay




















    6.2: Model–view–controller
    (经典的网站UI分层)

    Model–view–controller (MVC) is a software architectural pattern for implementing user interfaces. It divides a given software application into three interconnected parts, so as to separate internal representations of information from the ways that information is presented to or accepted from the user.[1][2] The central component, the model, consists of application data, business rules, logic and functions. A view can be any output representation of information, such as a chart or a diagram. Multiple views of the same information are possible, such as a bar chart for management and a tabular view for accountants. The third part, the controller, accepts input and converts it to commands for the model or view.



    In addition to dividing the application into three kinds of components, the model–view–controller design defines the interactions between them.[4]
    • A controller can send commands to the model to update the model's state (e.g., editing a document). It can also send commands to its associated view to change the view's presentation of the model (e.g., by scrolling through a document).
    • A model notifies its associated views and controllers when there has been a change in its state. This notification allows the views to produce updated output, and the controllers to change the available set of commands. In some cases an MVC implementation might instead be "passive," so that other components must poll the model for updates rather than being notified.
    • A view requests information from the model that it needs for generating an output representation to the user.

     


    6.3: Internet Layers Design Pattern
    (经典的互联网分层设计)
      
    5-Layer:
    • 5: Process & Applications
    • 4: TCP/IP
    • 3: Internet (MAC)
    • 2:  Network
    • 1:    Physical  
    7-Layer:

     6.4: Event-based Design Pattern (or Event-driven architecture)
     (事情响应机制)
    There are four types of objects: 
    • Events  
    • Event List
    • Event Scheduler
    • Events Handler
    It is widely used in Windows OS, UI, Java, etc.













    6.5: Peer-to-peer Design (or Peer-to-peer architecture)

     (纯分布式系统)

    The most common type of structured P2P networks implement a distributed hash table (DHT),[23][24] in which a variant of consistent hashing is used to assign ownership of each file to a particular peer.[25][26] This enables peers to search for resources on the network using a hash table: that is, (key, value) pairs are stored in the DHT, and any participating node can efficiently retrieve the value associated with a given key.

    Example: Chord

    Chord is a protocol and algorithm for a peer-to-peer distributed hash table. A distributed hash table stores key-value pairs by assigning keys to different computers (known as "nodes"); a node will store the values for all the keys for which it is responsible. Chord specifies how keys are assigned to nodes, and how a node can discover the value for a given key by first locating the node responsible for that key.

    Step 1:
    IDs and keys are assigned an m-bit identifier using consistent hashing. The SHA-1 algorithm is the base hashing function for consistent hashing.

    Step 2:
    Each node has a successor and a predecessor. The successor to a node (or key) is the next node in the identifier circle in a clockwise direction. The predecessor is counter-clockwise. 

    Step 3:
    A logical ring with positions numbered 0 to 2^{m}-1 is formed among nodes. Key k is assigned to node successor(k), which is the node whose identifier is equal to or follows the identifier of k. If there are N nodes and K keys, then each node is responsible for roughly K/N keys.

    Step 4:
    With high probability, Chord contacts O(\log N) nodes to find a successor in an N-node network.















    Example: Chord Design





    No comments:

    Post a Comment