学习笔记32-设计模式

来源:互联网 发布:创盈门窗软件 编辑:程序博客网 时间:2024/06/05 03:00

设计模式(Designs Patterns)

设计模式,可以理解为一些面向对象代码设计的经验的总结。
使用设计模式,是为了可重用代码,使代码更容易被人理解,保证代码的可靠性。
JAVA常用的设计模式有23种,这里准备用C++实现。

分类

总体来说,设计模式分为三类:

1. 创建型

这种模式在创建对象的时候隐藏了创建的逻辑,不是使用new操作符直接实例化对象。使得程序在判断针对某个实例应该创建那些对象时更加灵活。
这种类别包含了下面这些模式:

(1)工厂模式(Factory Pattern)

工厂模式分为三类:简单工厂模式、工厂方法模式、抽象工厂模式。
它的主要特点是需要在工厂类中做判断,从而创造相应的产品。当增加新的产品时,就需要修改工厂类。
比如下面的例子:

enum CTYPE {COREA, COREB};class SingleCore    {public:        virtual void Show() = 0;  };    //单核A    class SingleCoreA: public SingleCore    {    public:        void Show() { cout<<"SingleCore A"<<endl; }    };    //单核B    class SingleCoreB: public SingleCore    {    public:        void Show() { cout<<"SingleCore B"<<endl; }    };    //唯一的工厂,可以生产两种型号的处理器核,在内部判断    class Factory    {    public:         SingleCore* CreateSingleCore(enum CTYPE ctype)        {            if(ctype == COREA) //工厂内部判断                return new SingleCoreA(); //生产核A            else if(ctype == COREB)                return new SingleCoreB(); //生产核B            else                return NULL;        }    };

就是说一个工厂,能够生成两种单核处理器,那么根据传入的参数判断需要生产的是哪一种处理器,创建A或者B对象。
下面给出它的UML图:
Factory Pattern
这种方法,当增加了一种新的核类型时,就需要修改工厂类。为了适应这种情况,出现了工厂方法模式:

(2)工厂方法模式(Factory Method)

工厂方法模式是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
还是上面的例子,如果老板决定让新增一个工厂,用来生产B处理器,原来的工厂专门生产A处理器。这样就不需要在工厂类中判断需要生产什么类型的处理器了,而是客户去选择工厂,要A处理器就去找A厂,要B处理器就去找B厂。

class SingleCore    {    public:        virtual void Show() = 0;  };    //单核A    class SingleCoreA: public SingleCore    {    public:        void Show() { cout<<"SingleCore A"<<endl; }    };    //单核B    class SingleCoreB: public SingleCore    {    public:        void Show() { cout<<"SingleCore B"<<endl; }    };    class Factory    {    public:        virtual SingleCore* CreateSingleCore() = 0;  };    //生产A核的工厂    class FactoryA: public Factory    {    public:        SingleCoreA* CreateSingleCore() { return new SingleCoreA; }    };    //生产B核的工厂    class FactoryB: public Factory    {    public:        SingleCoreB* CreateSingleCore() { return new SingleCoreB; }    };    

这种模式也有缺点,每增加一种产品,就需要增加一个对象的工厂。如果这家公司发展迅速,推出了很多新的处理器核,那么就要开设相应的新工厂。在C++实现中,就是要定义一个个的工厂类。显然,相比简单工厂模式,工厂方法模式需要更多的类定义。
下面是它的UML图:
Factory Method

(3)抽象工厂模式(Abstract Factory Pattern)

但是,如果这家公司的技术不断进步,不仅可以生产单核处理器,也能生产多核处理器。现在简单工厂模式和工厂方法模式都鞭长莫及。抽象工厂模式登场了。它的定义为提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。具体这样应用,这家公司还是开设两个工厂,一个专门用来生产A型号的单核多核处理器,而另一个工厂专门用来生产B型号的单核多核处理器。

//单核    class SingleCore     {    public:        virtual void Show() = 0;  };    class SingleCoreA: public SingleCore      {    public:        void Show() { cout<<"Single Core A"<<endl; }    };    class SingleCoreB :public SingleCore    {    public:        void Show() { cout<<"Single Core B"<<endl; }    };    //多核    class MultiCore      {    public:        virtual void Show() = 0;  };    class MultiCoreA : public MultiCore      {    public:        void Show() { cout<<"Multi Core A"<<endl; }    };    class MultiCoreB : public MultiCore      {    public:        void Show() { cout<<"Multi Core B"<<endl; }    };    //工厂    class CoreFactory      {    public:        virtual SingleCore* CreateSingleCore() = 0;      virtual MultiCore* CreateMultiCore() = 0;  };    //工厂A,专门用来生产A型号的处理器    class FactoryA :public CoreFactory    {    public:        SingleCore* CreateSingleCore() { return new SingleCoreA(); }        MultiCore* CreateMultiCore() { return new MultiCoreA(); }    };    //工厂B,专门用来生产B型号的处理器    class FactoryB : public CoreFactory    {    public:        SingleCore* CreateSingleCore() { return new SingleCoreB(); }        MultiCore* CreateMultiCore() { return new MultiCoreB(); }    };

下面是它的UML图:
Abstract Factory

(4)单例模式(Singleton Pattern)

对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。

简单来说,单例模式有三个要点:
1. 某个类只能有一个实例
2. 它必须自己创建这个实例
3. 它必须自己向整个系统提供这个实例

从具体实现的角度,三个要点就是:
1. 单例模式中的类只提供私有的构造函数
2. 类定义中必须含有一个该类的静态私有对象
3. 该类必须提供一个静态的公有的函数用于创建或者获取它本身的私有对象

下面看一个具体的例子:

//Singleton.h  class Singleton    {  public:      static Singleton* GetInstance();  //公有的函数用于创建或者获取私有对象private:      Singleton() {}                    //私有构造函数    static Singleton *singleton;      //私有对象};  //Singleton.cpp  Singleton* Singleton::singleton = NULL;  Singleton* Singleton::GetInstance()  {      if(singleton == NULL)          singleton = new Singleton();      return singleton;  } 

UML图:
Singleton

(5)建造者模式(Builder Pattern)

建造者模式,可以简单理解为:
建筑工人建造楼房的时候,不同的楼房千差万别,但是抽象出来的建筑流程是一样的:
打桩———–>建造钢筋框架———->建筑混凝土墙体
也就是说,建造者模式保证了流程不变:
即流程不会增加,不会遗漏,也不会产生顺序错乱
但是,每个流程具体的实现细节是经常变化的。
建造者模式通常包括下面几个部分:
1. Builder (建造者):就是一个抽象的接口,规定要实现复杂对象的哪些部分的创建,但是不涉及具体的实现细节。
2. Concrete Builder(具体建造者):就是上面的接口的实现,针对不同的业务逻辑,具体化复杂对象各个部分的创建,建造完成后,提供产品的实例。
3. Director (指导者):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品信息,只负责保证对象各部分的完整创建和创建顺序。
4. Product (产品):就是要创建的复杂对象。
下面给出UML图:
Builder

最后给个例子:
比如游戏开发中建造小人,小人必须包括头,身体,手和脚,但是具体系统要求有胖人和瘦人。建造者模式代码如下:

#include <iostream>#include <vector>#include <string>using namespace std;//Product类class Product{    vector<string> parts;public:    void Add(const string part)    {        parts.push_back(part);    }    void Show()const    {        for(int i = 0 ; i < parts.size() ; i++)        {            cout<<parts[i]<<endl;        }    }};//抽象builder类  都用纯虚函数 相当于Java中的接口class Builder{public:    virtual void BuildHead() = 0;    virtual void BuildBody() = 0;    virtual void BuildHand() = 0;    virtual void BuildFeet() = 0;    virtual Product GetResult() = 0; };//具体胖人创建类    继承自builderclass FatPersonBuilder :public Builder{private:    Product product;public:    virtual void BuildHead()    {        product.Add("胖人头");//创建瘦人的头    }    virtual void BuildBody()    {        product.Add("胖人身体");//创建瘦人的身体    }    virtual void BuildHand()    {        product.Add("胖人手");//创建瘦人的手    }    virtual void BuildFeet()    {        product.Add("胖人脚");//创建瘦人的脚    }    virtual Product GetResult()    {        return product;    }};//具体瘦人人创建类class ThinPersonBuilder :public Builder{private:    Product product;public:    virtual void BuildHead()    {        product.Add("瘦人人头");//创建瘦人的头    }    virtual void BuildBody()    {        product.Add("瘦人身体");//创建瘦人的身体    }    virtual void BuildHand()    {        product.Add("瘦人手");//创建瘦人的手    }    virtual void BuildFeet()    {        product.Add("瘦人脚");//创建瘦人的脚    }    virtual Product GetResult()    {        return product;    }};//Director类class Director{public:    void Construct(Builder &builder)    {        builder.BuildHead();        builder.BuildBody();        builder.BuildHand();        builder.BuildFeet();    }};int main(){    Director *director = new Director();    Builder *b1 = new FatPersonBuilder();    Builder *b2 = new ThinPersonBuilder();    director->Construct(*b2);    Product p1 = b2->GetResult();    p1.Show();     return 0;}

建造者模式有以下好处:

  1. 使用建造者模式可以使客户端不必知道产品内部组成的细节。
  2. 具体的建造者类之间是相互独立的,对系统的扩展非常有利。
  3. 由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。

使用建造者模式的场合主要有:
1. 创建一些复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象的内部组成构件面临着复杂的变化。
2. 要创建的复杂对象的算法,独立于该对象的组成部分,也独立于组成部分的装配方法时。

(6)原型模式(Prototype Pattern)

2. 结构型

(1)适配器模式(Adapter Pattern)

(2)桥接模式(Bridge Pattern)

(3)过滤器模式(Filter、Criteria Pattern)

(4)组合模式(Composite Pattern)

(5)装饰器模式(Decorator Pattern)

(6)外观模式(Facade Pattern)

(7)享元模式(Flyweight Pattern)

(8)代理模式(Proxy Pattern)

3. 行为型
(1)责任链模式(Chain of Responsibility Pattern)

(2)命令模式(Command Pattern)

(3)解释器模式(Interpreter Pattern)

(4)迭代器模式(Iterator Pattern)

(5)中介者模式(Mediator Pattern)

(6)备忘录模式(Memento Pattern)

(7)观察者模式(Observer Pattern)

(8)状态模式(State Pattern)

(9)空对象模式(Null Object Pattern)

(10)策略模式(Strategy Pattern)

(11)模板模式(Template Pattern)

(12)访问者模式(Visitor Pattern)

原创粉丝点击