设计模式

面向对象编程的核心思想--高内聚低耦合。
设计模式的大部分作用就是解耦、功能逻辑分离、责任划分。

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。

批注:面向接口编程,功能逻辑分离。

6种设计原则

单一职责原则

单一职责原则的英文名称是Single Responsibility Principle,简称是SRP。这个原则存在争议之处在于对职责的定义,什么是类的职责,以及怎么划分类的职责。

单一职责原则的好处:

  • 类的复杂性降低,实现什么职责都有清晰明确的定义;
  • 可读性提高,复杂性降低,那当然可读性提高了;
  • 可维护性提高,可读性提高,那当然更容易维护了;
  • 变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。

注意 单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。

对于单一职责原则,我的建议是接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。

里氏替换原则

里氏替换原则(Liskov Substitution Principle,LSP)有两个定义。

第一种定义,也是最正宗的定义:
If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T,the behavior of P is unchanged when o1 is substituted for >o2 then S is a subtype of T.

如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。

第二种定义:
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

所有引用基类的地方必须能透明地使用其子类的对象。

第二个定义是最清晰明确的,通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。

注意 如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。

依赖倒置原则

依赖倒置原则(Dependence Inversion Principle,DIP)

High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.

翻译过来,包含三层含义:
1.高层模块不应该依赖低层模块,两者都应该依赖其抽象;
2.抽象不应该依赖细节;
3.细节应该依赖抽象。

依赖倒置原则在Java语言中的表现就是:

  • 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;
  • 接口或抽象类不依赖于实现类;
  • 实现类依赖接口或抽象类。

依赖倒置原则的优点:

  • 依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。
  • 减少并行开发引起的风险。

依赖的三种写法

  1. 构造函数传递依赖对象;
  2. Setter方法传递依赖对象;
  3. 接口声明依赖对象。

规则

  1. 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备。
  2. 变量的表面类型尽量是接口或者是抽象类。
  3. 任何类都不应该从具体类派生。
  4. 尽量不要覆写基类的方法。
  5. 结合里氏替换原则使用。

接口隔离原则

接口:
实例接口(Object Interface)和类接口(Class Interface)。

隔离:
Clients should not be forced to depend upon interfaces that they don't use.
客户端不应该依赖它不需要的接口。
The dependency of one class to another one should depend on the smallest possible interface.
类间的依赖关系应该建立在最小的接口上。

在实践中可以根据以下几个规则来衡量:

  • 一个接口只服务于一个子模块或业务逻辑;
  • 通过业务逻辑压缩接口中的public方法,接口时常去回顾,尽量让接口达到“满身筋骨肉”,而不是“肥嘟嘟”的一大堆方法;
  • 已经被污染了的接口,尽量去修改,若变更的风险较大,则采用适配器模式进行转化处理;
  • 了解环境,拒绝盲从。每个项目或产品都有特定的环境因素,别看到大师是这样做的你就照抄。千万别,环境不同,接口拆分的标准就不同。深入了解业务逻辑,最好的接口设计就出自你的手中!

迪米特法则

迪米特法则(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge Principle,LKP),虽然名字不同,但描述的是同一个规则:一个对象应该对其他对象有最少的了解。通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我没关系,那是你的事情,我就知道你提供的这么多public方法,我就调用这么多,其他的我一概不关心。

迪米特法则要求类“羞涩”一点,尽量不要对外公布太多的public方法和非静态的public变量,尽量内敛,多使用private、package-private、protected等访问权限。

一个类公开的public属性或方法越多,修改时涉及的面也就越大,变更引起的风险扩散也就越大。因此,为了保持朋友类间的距离,在设计时需要反复衡量:是否还可以再减少public方法和属性,是否可以修改为private、package-private(包类型,在类、方法、变量前不加访问权限,则默认为包类型)、protected等访问权限,是否可以加上final关键字等。

总之,高内聚低耦合,一个类应该减少对外公开的接口,做到即使改变也不会影响其他类。

开闭原则

Software entities like classes,modules and functions should be open for extension but closed for modifications.

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

开闭原则对扩展开放,对修改关闭,并不意味着不做任何修改,低层模块的变更,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。

通过扩展来实现业务逻辑的变化,而不是修改。

23种设计模式归类

创建型模式

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

  • 工厂方法模式(Factory Method Pattern)★★★★★
  • 抽象工厂模式(Abstract Factory Pattern)★★★★★
  • 单例模式(Singleton Pattern)★★★★☆
  • 建造者模式(Builder Pattern)★★☆☆☆
  • 原型模式(Prototype Pattern)★★★☆☆

结构型模式

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

  • 适配器模式(Adapter Pattern)★★★★☆
  • 桥接模式(Bridge Pattern)★★★☆☆
  • 过滤器模式(Filter、Criteria Pattern)
  • 组合模式(Composite Pattern)★★★★☆
  • 装饰器模式(Decorator Pattern)★★★☆☆
  • 外观模式(Facade Pattern)★★★★★
  • 享元模式(Flyweight Pattern)★☆☆☆☆
  • 代理模式(Proxy Pattern)★★★★☆

行为型模式

这些设计模式特别关注对象之间的通信。

  • 责任链模式(Chain of Responsibility Pattern)★★☆☆☆
  • 命令模式(Command Pattern)★★★★☆
  • 解释器模式(Interpreter Pattern)★☆☆☆☆
  • 迭代器模式(Iterator Pattern)★★★★★
  • 中介者模式(Mediator Pattern)★★☆☆☆
  • 备忘录模式(Memento Pattern)★★☆☆☆
  • 观察者模式(Observer Pattern)★★★★★
  • 状态模式(State Pattern)★★★☆☆
  • 空对象模式(Null Object Pattern)
  • 策略模式(Strategy Pattern)★★★★☆
  • 模板模式(Template Pattern)★★★☆☆
  • 访问者模式(Visitor Pattern)★☆☆☆☆

J2EE 模式

这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。

  • MVC 模式(MVC Pattern)
  • 业务代表模式(Business Delegate Pattern)
  • 组合实体模式(Composite Entity Pattern)
  • 数据访问对象模式(Data Access Object Pattern)
  • 前端控制器模式(Front Controller Pattern)
  • 拦截过滤器模式(Intercepting Filter Pattern)
  • 服务定位器模式(Service Locator Pattern)
  • 传输对象模式(Transfer Object Pattern)

23种设计模式解析

单例模式

Ensure a class has only one instance, and provide a global point of access to it.

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

Singleton类称为单例类,通过使用private的构造函数确保了在一个应用中只产生一个实例,并且是自行实例化的。


应用案例:总线模式。总线模式在全局中是唯一的,所有消息向总线注册,再由总线分发。

#include <iostream>

class Singleton
{
public:
    ~Singleton(){
        std::cout<<"destructor called!"<<std::endl;
    }
    Singleton(const Singleton&)=delete;
    Singleton& operator=(const Singleton&)=delete;
    static Singleton& get_instance(){
        static Singleton instance;
        return instance;

    }
//构造函数由private修饰
private:
    Singleton(){
        std::cout<<"constructor called!"<<std::endl;
    }
};

int main(int argc, char *argv[])
{
    Singleton& instance_1 = Singleton::get_instance();
    Singleton& instance_2 = Singleton::get_instance();
    return 0;
}
constructor called!
destructor called!

工厂方法模式

Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

为什么要用工厂模式?
对于大型工程,掌握整个工程是很难的,工厂模式的好处是,将所有要初始化的对象都集中在一起,然后使用一个对象可以索引出他们,避免到处寻找要初始化的对象,就可以无需思考无脑初始化对象了。

优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

工厂方法模式通用类图


main(),女娲

IHuman,产品接口

CYellowHuman,产品之一

CWhiteHuman,产品之二

CBlackHuman,产品之三

IHumanFactory,工厂接口

CYellowHumanFactory,工厂之一

CWhiteHumanFactory,工厂之二

CBlackHumanFactory,工厂之三

女娲造人图

批注:工厂类提供了方法createHuman()来new一个产品类(如CYellowHuman),但是这里的例子并没有体现出工厂类的优势,只是简单介绍了其使用方法。如果工厂类单纯用createHuman()实现了new一个产品类,那么还不如直接new一个产品类。

其实工厂模式也是功能逻辑分离的一种体现,产品类单纯负责new一个产品,而工厂类应有额外的业务逻辑处理,如有效性判断,返回实例名称等。

IHuman.h

#pragma once
class IHuman
{
public:
    IHuman(void)
    {
    }
    virtual ~IHuman(void)
    {
    }
    virtual void Laugh() = 0;
    virtual void Cry() = 0;
    virtual void Talk() = 0;
};

YellowHuman.h

#pragma once
#include "ihuman.h"
class CYellowHuman :
    public IHuman
{
public:
    CYellowHuman(void);
    ~CYellowHuman(void);
    void Laugh();
    void Cry();
    void Talk();
};

YellowHuman.cpp

#include <stdio.h>
#include "YellowHuman.h"
#include <iostream>
using std::cout;
using std::endl;
CYellowHuman::CYellowHuman(void)
{
}
CYellowHuman::~CYellowHuman(void)
{
}
void CYellowHuman::Cry()
{
    cout << "黄色人种会哭" << endl;
}
void CYellowHuman::Laugh()
{
    cout << "黄色人种会大笑,幸福呀!" << endl;
}
void CYellowHuman::Talk()
{
    cout << "黄色人种会说话,一般说的都是双字节" << endl;
}

WhiteHuman.h

#pragma once
#include "ihuman.h"
class CWhiteHuman :
    public IHuman
{
public:
    CWhiteHuman(void);
    ~CWhiteHuman(void);
    void Laugh();
    void Cry();
    void Talk();
};

WhiteHuman.cpp

#include <stdio.h>
#include "WhiteHuman.h"
#include <iostream>
using std::cout;
using std::endl;
CWhiteHuman::CWhiteHuman(void)
{
}
CWhiteHuman::~CWhiteHuman(void)
{
}
void CWhiteHuman::Cry()
{
    cout << "白色人种会哭" << endl;
}
void CWhiteHuman::Laugh()
{
    cout << "白色人种会大笑,侵略的笑声" << endl;
}
void CWhiteHuman::Talk()
{
    cout << "白色人种会说话,一般都是单字节" << endl;
}

BlackHuman.h

#pragma once
#include "ihuman.h"
class CBlackHuman :
    public IHuman
{
public:
    CBlackHuman(void);
    ~CBlackHuman(void);
    void Laugh();
    void Cry();
    void Talk();
};

BlackHuman.cpp

#include <stdio.h>
#include "BlackHuman.h"
#include <iostream>
using std::cout;
using std::endl;
CBlackHuman::CBlackHuman(void)
{
}
CBlackHuman::~CBlackHuman(void)
{
}
void CBlackHuman::Cry()
{
    cout << "黑人会哭" << endl;
}
void CBlackHuman::Laugh()
{
    cout << "黑人会笑" << endl;
}
void CBlackHuman::Talk()
{
    cout << "黑人可以说话,一般人听不懂" << endl;
}

IHumanFactory.h

#pragma once
#include "IHuman.h"
class IHumanFactory
{
public:
    IHumanFactory(void)
    {
    }
    virtual ~IHumanFactory(void)
    {
    }
    virtual IHuman * CreateHuman() = 0;
};

YellowHumanFactory.h

#pragma once
#include "ihumanfactory.h"
class CYellowHumanFactory :
    public IHumanFactory
{
public:
    CYellowHumanFactory(void);
    ~CYellowHumanFactory(void);
    virtual IHuman * CreateHuman(void);
};

YellowHumanFactory.cpp

#include <stdio.h>
#include "YellowHumanFactory.h"
#include "YellowHuman.h"
CYellowHumanFactory::CYellowHumanFactory(void)
{
}
CYellowHumanFactory::~CYellowHumanFactory(void)
{
}
IHuman * CYellowHumanFactory::CreateHuman( void )
{
    //理论上这里应该有业务逻辑处理,比如打印实例名称,有效性判断等。
    return new CYellowHuman();
}

WhiteHumanFactory.h

#pragma once
#include "ihumanfactory.h"
class CWhiteHumanFactory :
    public IHumanFactory
{
public:
    CWhiteHumanFactory(void);
    ~CWhiteHumanFactory(void);
    virtual IHuman * CreateHuman(void);
};

WhiteHumanFactory.cpp

#include <stdio.h>
#include "WhiteHumanFactory.h"
#include "WhiteHuman.h"
CWhiteHumanFactory::CWhiteHumanFactory(void)
{
}
CWhiteHumanFactory::~CWhiteHumanFactory(void)
{
}
IHuman * CWhiteHumanFactory::CreateHuman( void )
{
    return new CWhiteHuman();
}

BlackHumanFactory.h

#pragma once
#include "ihumanfactory.h"
class CBlackHumanFactory :
    public IHumanFactory
{
public:
    CBlackHumanFactory(void);
    ~CBlackHumanFactory(void);
    virtual IHuman * CreateHuman();
};

BlackHumanFactory.cpp

#include <stdio.h>
#include "BlackHumanFactory.h"
#include "BlackHuman.h"
CBlackHumanFactory::CBlackHumanFactory(void)
{
}
CBlackHumanFactory::~CBlackHumanFactory(void)
{
}
IHuman * CBlackHumanFactory::CreateHuman()
{
    return new CBlackHuman();
}

NvWa.cpp

#include <stdio.h>
#include "IHuman.h"
#include "YellowHuman.h"
#include "WhiteHuman.h"
#include "BlackHuman.h"
#include "IHumanFactory.h"
#include "YellowHumanFactory.h"
#include "WhiteHumanFactory.h"
#include "BlackHumanFactory.h"
#include <iostream>
using std::cout;
using std::endl;
using std::string;

int main()
{
    //工厂方法
    cout << "----------工厂方法:" << endl;

    cout << "----------第一批人是这样的:黄种人工厂来生产黄种人" << endl;
    IHumanFactory *pHumanFactory = new CYellowHumanFactory();
    IHuman *pHuman = pHumanFactory->CreateHuman();
    pHuman->Cry();
    pHuman->Laugh();
    pHuman->Talk();
    delete pHuman;
    delete pHumanFactory;

    cout << "----------第二批人是这样的:白种人工厂来生产白种人" << endl;
    IHumanFactory *pHumanFactory = new CWhiteHumanFactory();
    IHuman *pHuman = pHumanFactory->CreateHuman();
    pHuman->Cry();
    pHuman->Laugh();
    pHuman->Talk();
    delete pHuman;
    delete pHumanFactory;

    cout << "----------第三批人是这样的:黑种人工厂来生产黑种人" << endl;
    IHumanFactory *pHumanFactory = new CBlackHumanFactory();
    IHuman *pHuman = pHumanFactory->CreateHuman();
    pHuman->Cry();
    pHuman->Laugh();
    pHuman->Talk();
    delete pHuman;
    delete pHumanFactory;

    return 0;
}
----------工厂方法:
----------第一批人是这样的:黄种人工厂来生产黄种人
黄色人种会哭
黄色人种会大笑,幸福呀!
黄色人种会说话,一般说的都是双字节
----------第二批人是这样的:白种人工厂来生产白种人
白色人种会哭
白色人种会大笑,侵略的笑声
白色人种会说话,一般都是单字节
----------第三批人是这样的:黑种人工厂来生产黑种人
黑人会哭
黑人会笑
黑人可以说话,一般人听不懂

抽象工厂模式

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。

抽象工厂,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。对于工厂方法来说,抽象工厂可实现一系列产品的生产,抽象工厂更注重产品的组合。

抽象工厂模式的通用类图

抽象工厂模式的通用源码类图

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

主要解决:主要解决接口选择的问题。

优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。


main(),女娲

IHuman,产品接口

CYellowHuman,抽象产品之一

CYellowFemaleHuman,具体产品之一

CYellowMaleHuman,具体产品之二

CWhiteHuman,抽象产品之二

CWhiteFemaleHuman,具体产品之三

CWhiteMaleHuman,具体产品之四

CBlackHuman,抽象产品之三

CBlackFemaleHuman,具体产品之五

CBlackMaleHuman,具体产品之六

IHumanFactory,抽象工厂

CStandardHumanFactory,抽象工厂基类(此类可有可无)

CFemaleHumanFactory,工厂之一

CMaleHumanFactory,工厂之二

女娲造人新图

IHuman.h

#pragma once
class IHuman
{
public:

    IHuman(void)
    {
    }

    virtual ~IHuman(void)
    {
    }

    virtual void Laugh() = 0;
    virtual void Cry() = 0;
    virtual void Talk() = 0;
    virtual void Sex() = 0;
};

YellowHuman.h

#pragma once
#include "ihuman.h"
#include <iostream>
using std::cout;
using std::endl;
class CYellowHuman :
    public IHuman
{
public:
    CYellowHuman(void)
    {
    }
    ~CYellowHuman(void)
    {
    }
    void Laugh()
    {
        cout << "黄色人种会大笑,幸福呀!" << endl;
    }
    void Cry()
    {
        cout << "黄色人种会哭" << endl;
    }
    void Talk()
    {
        cout << "黄色人种会说话,一般说的都是双字节" << endl;
    }
    virtual void Sex() = 0;
};

YellowFemaleHuman.h

#pragma once
#include "yellowhuman.h"
#include <iostream>
using std::cout;
using std::endl;
class CYellowFemaleHuman :
    public CYellowHuman
{
public:
    CYellowFemaleHuman(void)
    {
    }
    ~CYellowFemaleHuman(void)
    {
    }
    void Sex()
    {
        cout << "该黄种人的性别为女..." << endl;
    }
};

YellowMaleHuman.h

#pragma once
#include "yellowhuman.h"
#include <iostream>
using std::cout;
using std::endl;
class CYellowMaleHuman :
    public CYellowHuman
{
public:
    CYellowMaleHuman(void)
    {
    }
    ~CYellowMaleHuman(void)
    {
    }
    void Sex()
    {
        cout << "该黄种人的性别为男..." << endl;
    }
};

WhiteHuman.h

#pragma once
#include "ihuman.h"
#include <iostream>
using std::cout;
using std::endl;
class CWhiteHuman :
    public IHuman
{
public:
    CWhiteHuman(void)
    {
    }
    ~CWhiteHuman(void)
    {
    }
    void Laugh()
    {
        cout << "白色人种会大笑,侵略的笑声" << endl;
    }
    void Cry()
    {
        cout << "白色人种会哭" << endl;
    }
    void Talk()
    {
        cout << "白色人种会说话,一般都是单字节" << endl;
    }
    virtual void Sex() = 0;
};

WhiteFemaleHuman.h

#pragma once
#include "whitehuman.h"
#include <iostream>
using std::cout;
using std::endl;
class CWhiteFemaleHuman :
    public CWhiteHuman
{
public:
    CWhiteFemaleHuman(void)
    {
    }
    ~CWhiteFemaleHuman(void)
    {
    }
    void Sex()
    {
        cout << "该白种人的性别为女..." << endl;
    }
};

WhiteMaleHuman.h

#pragma once
#include "whitehuman.h"
#include <iostream>
using std::cout;
using std::endl;
class CWhiteMaleHuman :
    public CWhiteHuman
{
public:
    CWhiteMaleHuman(void)
    {
    }
    ~CWhiteMaleHuman(void)
    {
    }
    void Sex()
    {
        cout << "该白种人的性别为男..." << endl;
    }
};

BlackHuman.h

#pragma once
#include "ihuman.h"
#include <iostream>
using std::cout;
using std::endl;
class CBlackHuman :
    public IHuman
{
public:
    CBlackHuman(void)
    {
    }
    ~CBlackHuman(void)
    {
    }
    void Laugh()
    {
        cout << "黑人会笑" << endl;
    }
    void Cry()
    {
        cout << "黑人会哭" << endl;
    }
    void Talk()
    {
        cout << "黑人可以说话,一般人听不懂" << endl;
    }

    virtual void Sex() = 0;
};

BlackFemaleHuman.h

#pragma once
#include "blackhuman.h"
#include <iostream>
using std::cout;
using std::endl;
class CBlackFemaleHuman :
    public CBlackHuman
{
public:
    CBlackFemaleHuman(void)
    {
    }
    ~CBlackFemaleHuman(void)
    {
    }
    void Sex()
    {
        cout << "该黑种人的性别为女..." << endl;
    }
};

BlackMaleHuman.h

#pragma once
#include "blackhuman.h"
#include <iostream>
using std::cout;
using std::endl;
class CBlackMaleHuman :
    public CBlackHuman
{
public:
    CBlackMaleHuman(void)
    {
    }
    ~CBlackMaleHuman(void)
    {
    }
    void Sex()
    {
        cout << "该黑种人的性别为男..." << endl;
    }
};

IHumanFactory.h

#pragma once
#include "IHuman.h"
class IHumanFactory
{
public:
    IHumanFactory(void)
    {
    }
    virtual ~IHumanFactory(void)
    {
    }
    virtual IHuman * CreateYellowHuman() = 0;
    virtual IHuman * CreateWhiteHuman() = 0;
    virtual IHuman * CreateBlackHuman() = 0;
};

MaleHumanFactory.h

#pragma once

#include "StandardHumanFactory.h"
#include "IHumanFactory.h"
template<class T>
class CMaleHumanFactory :
   public IHumanFactory
{
public:
   CMaleHumanFactory(void)
   {
   }
   ~CMaleHumanFactory(void)
   {
   }
   IHuman* CreateYellowHuman()
   {
      return new T;
   }
   IHuman* CreateWhiteHuman()
   {
      return new T;
   }
   IHuman* CreateBlackHuman()
   {
      return new T;
   }
};

FemaleHumanFactory.h

#pragma once
#include "standardhumanfactory.h"
template<class T>
class CFemaleHumanFactory :
   public IHumanFactory
{
public:
   CFemaleHumanFactory(void)
   {
   }
   ~CFemaleHumanFactory(void)
   {
   }
   IHuman* CreateYellowHuman()
   {
      return new T;
   }
   IHuman* CreateWhiteHuman()
   {
      return new T;
   }
   IHuman* CreateBlackHuman()
   {
      return new T;
   }
};

main.cpp

#include <stdio.h>
#include "IHuman.h"
#include "IHumanFactory.h"
#include "FemaleHumanFactory.h"
#include "MaleHumanFactory.h"
#include "yellowhuman.h"
#include "YellowFemaleHuman.h"
#include "YellowMaleHuman.h"
#include "whitehuman.h"
#include "WhiteFemaleHuman.h"
#include "WhiteMaleHuman.h"
#include "blackhuman.h"
#include "BlackFemaleHuman.h"
#include "BlackMaleHuman.h"

int main()
{
   IHumanFactory* pFemaleHumanFactory = new CFemaleHumanFactory<CYellowFemaleHuman>();
   IHuman* pYellowFemaleHuman = pFemaleHumanFactory->CreateYellowHuman();
   pYellowFemaleHuman->Cry();
   pYellowFemaleHuman->Laugh();
   pYellowFemaleHuman->Talk();
   pYellowFemaleHuman->Sex();
   delete pYellowFemaleHuman;
   delete pFemaleHumanFactory;

   IHumanFactory* pMaleHumanFactory = new CMaleHumanFactory<CYellowMaleHuman>();
   IHuman* pYellowMaleHuman = pMaleHumanFactory->CreateYellowHuman();
   pYellowMaleHuman->Cry();
   pYellowMaleHuman->Laugh();
   pYellowMaleHuman->Talk();
   pYellowMaleHuman->Sex();
   delete pYellowMaleHuman;
   delete pMaleHumanFactory;

   return 0;
}
黄色人种会哭
黄色人种会大笑,幸福呀!
黄色人种会说话,一般说的都是双字节
该黄种人的性别为女...
黄色人种会哭
黄色人种会大笑,幸福呀!
黄色人种会说话,一般说的都是双字节
该黄种人的性别为男...

模板方法模式

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)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。

优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。

缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。


main(),客户

CHummerModel,悍马模型

CHummerH1Model,悍马模型型号1

CHummerH2Model,悍马模型型号2

说明:在CHummerModel声明Start、Engineboom、Alarm、Stop虚函数,由派生类实现。基类的Run负责组织逻辑,分别调用这几个派生类实现的函数。

注意:基类中的Run应该禁止派生类覆盖。
悍马车模类图

HummerModel.h

#pragma once
class CHummerModel
{
public:
    CHummerModel(void);
    virtual ~CHummerModel(void);
    void Run();
protected:
    virtual void Start() = 0;
    virtual void Stop() = 0;
    virtual void Alarm() = 0;
    virtual void EngineBoom() = 0;
    virtual bool IsAlarm();
};

HummerModel.cpp

#include <stdio.h>
#include "HummerModel.h"
#include <iostream>
using std::cout;
using std::endl;
CHummerModel::CHummerModel(void)
{
}
CHummerModel::~CHummerModel(void)
{
}
void CHummerModel::Run()
{
    //先发动汽车
    Start();
    //引擎开始轰鸣
    EngineBoom();
    //然后就开始跑了,跑的过程中遇到一条狗挡路,就按喇叭
    if (IsAlarm())
        Alarm();

    //到达目的地就停车
    Stop();
}
bool CHummerModel::IsAlarm()
{
    //钩子方法,默认喇叭是会响的
    return true;
}

HummerH1Model.h

#pragma once
#include "hummermodel.h"
class CHummerH1Model :
    public CHummerModel
{
public:
    CHummerH1Model(void);
    ~CHummerH1Model(void);
    void SetAlarm(bool tag);
    void Start();
    void Stop();
    void Alarm();
    void EngineBoom();
    bool IsAlarm();
private:
    bool m_isAlarm;
};

HummerH1Model.cpp

#include <stdio.h>
#include "HummerH1Model.h"
#include <iostream>
using std::cout;
using std::endl;
CHummerH1Model::CHummerH1Model(void)
{
    m_isAlarm = true;
}
CHummerH1Model::~CHummerH1Model(void)
{
}
void CHummerH1Model::Start()
{
    cout << "悍马H1发动..." << endl;
}
void CHummerH1Model::Stop()
{
    cout << "悍马H1停车..." << endl;
}
void CHummerH1Model::Alarm()
{
    cout << "悍马H1鸣笛" << endl;
}
void CHummerH1Model::EngineBoom()
{
    cout << "悍马H1引擎声音是这样...." << endl;
}
bool CHummerH1Model::IsAlarm()
{
    return this->m_isAlarm;
}
void CHummerH1Model::SetAlarm( bool tag )
{
    this->m_isAlarm = tag;
}

HummerH2Model.h

#pragma once
#include "hummermodel.h"
class CHummerH2Model :
    public CHummerModel
{
public:
    CHummerH2Model(void);
    ~CHummerH2Model(void);
    void Start();
    void Stop();
    void Alarm();
    void EngineBoom();
    bool IsAlarm();
};

HummerH2Model.cpp

#include <stdio.h>
#include "HummerH2Model.h"
#include <iostream>
using std::cout;
using std::endl;
CHummerH2Model::CHummerH2Model(void)
{
}
CHummerH2Model::~CHummerH2Model(void)
{
}
void CHummerH2Model::Start()
{
    cout << "悍马H2发动..." << endl;
}
void CHummerH2Model::Stop()
{
    cout << "悍马H2停车..." << endl;
}
void CHummerH2Model::Alarm()
{
    cout << "悍马H2鸣笛" << endl;
}
void CHummerH2Model::EngineBoom()
{
    cout << "悍马H2引擎声音是这样...." << endl;
}
bool CHummerH2Model::IsAlarm()
{
    return false;
}

TemplateMethod.cpp

#include <stdio.h>
#include "HummerModel.h"
#include "HummerH1Model.h"
#include "HummerH2Model.h"
#include <crtdbg.h>
int main()
{
    //客户开着H1型号,出去遛弯了
    CHummerModel *ph1 = new CHummerH1Model();
    ph1->Run();
    delete ph1;

    //客户开H2型号,出去玩耍了
    CHummerModel *ph2 = new CHummerH2Model();
    ph2->Run();
    delete ph2;

    //客户开着H1型号,出去遛弯了,并且不让喇叭响
    CHummerH1Model *ph11 = new CHummerH1Model();
    ph11->SetAlarm(false);
    ph11->Run();
    delete ph11;

    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
    _CrtDumpMemoryLeaks();
    return 0;
}
悍马H1发动...
悍马H1引擎声音是这样....
悍马H1鸣笛
悍马H1停车...悍马H2发动...悍马H2引擎声音是这样....
悍马H2停车...悍马H1发动...悍马H1引擎声音是这样....
悍马H1停车...

建造者模式

Separate the construction of a complex object from its representation so that the same construction process can create different representations.

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。


main(),客户

CCarModel,产品模型

CBenzModel,奔驰模型

CBMWModel,宝马模型

ICarBuilder,建造者接口

CBenzBuilder,奔驰建造者

CBMWBuilder,宝马建造者

CDirector,导演

说明:CCarModel实现模板方法,Builder负责开始建造产品。建造产品时,构建的顺序由Director或main决定。

注意:建造者模式和抽象工厂非常类似。建造者更重视产品建造时的逻辑顺序,而抽象工厂更重视生产出不同型号的产品,抽象工厂不关心顺序。

批注:还是功能逻辑分离思想,将功能划分为最小功能单元,在逻辑层根据业务员要求重新组合。比如奔驰车要求启动时鸣笛,宝马车要求启动时开闪光。
汽车模型类图

CarModel.h

#pragma once
#include <vector>
#include <iostream>
using std::vector;
using std::string;
class CCarModel
{
public:
    CCarModel(void);
    virtual ~CCarModel(void);
    void Run();
    void SetSequence(vector<string> *pSeq);
protected:
    virtual void Start() = 0;
    virtual void Stop() = 0;
    virtual void Alarm() = 0;
    virtual void EngineBoom() = 0;
private:
    vector<string> * m_pSequence;
};

CarModel.cpp

#include <stdio.h>
#include "CarModel.h"
#include <vector>
#include <iostream>
using std::vector;
using std::string;
CCarModel::CCarModel(void)
{
}
CCarModel::~CCarModel(void)
{
}
void CCarModel::SetSequence(vector<string> *pSeq)
{
    m_pSequence = pSeq;
}
void CCarModel::Run()
{
    vector<string>::const_iterator it = m_pSequence->begin();
    for (; it < m_pSequence->end(); ++it)
    {
        string actionName = *it;
        if(actionName.compare("start") == 0)
        {
            Start();
        }
        else if(actionName.compare("stop") == 0)
        {
            Stop();
        }
        else if(actionName.compare("alarm") == 0)
        {
            Alarm();
        }
        else if(actionName.compare("engine boom") == 0)
        {
            EngineBoom();
        }
    }
}

BenzModel.h

#pragma once
#include "carmodel.h"
class CBenzModel :
    public CCarModel
{
public:
    CBenzModel(void);
    ~CBenzModel(void);
protected:
    void Start();
    void Stop();
    void Alarm();
    void EngineBoom();
};

BenzModel.cpp

#include <stdio.h>
#include "BenzModel.h"
#include <iostream>
using std::cout;
using std::endl;
CBenzModel::CBenzModel()
{
}
CBenzModel::~CBenzModel()
{
}
void CBenzModel::Start()
{
   cout << "奔驰发动..." << endl;
}
void CBenzModel::Stop()
{
   cout << "奔驰停车..." << endl;
}
void CBenzModel::Alarm()
{
   cout << "奔驰鸣笛" << endl;
}
void CBenzModel::EngineBoom()
{
   cout << "奔驰引擎声音是这样...." << endl;
}

BMWModel.h

#pragma once
#include "carmodel.h"
class CBMWModel :
    public CCarModel
{
public:
    CBMWModel(void);
    ~CBMWModel(void);
protected:
    void Start();
    void Stop();
    void Alarm();
    void EngineBoom();
};

BMWModel.cpp

#include <stdio.h>
#include "BMWModel.h"
#include <iostream>
using std::cout;
using std::endl;
CBMWModel::CBMWModel(void)
{
}
CBMWModel::~CBMWModel(void)
{
}
void CBMWModel::Start()
{
    cout << "宝马发动..." << endl;
}
void CBMWModel::Stop()
{
    cout << "宝马停车..." << endl;
}
void CBMWModel::Alarm()
{
    cout << "宝马鸣笛" << endl;
}
void CBMWModel::EngineBoom()
{
    cout << "宝马引擎声音是这样...." << endl;
}

ICarBuilder.h

#pragma once
#include "CarModel.h"
#include <iostream>
#include <vector>
using std::string;
using std::vector;
class ICarBuilder
{
public:
    ICarBuilder(void)
    {
    }
    virtual ~ICarBuilder(void)
    {
    }
    virtual void SetSequence(vector<string> *pseq) = 0;
    virtual CCarModel * GetCarModel() = 0;
};

BenzBuilder.h

#pragma once
#include "icarbuilder.h"
#include "CarModel.h"
#include <iostream>
#include <vector>
using std::string;
using std::vector;
class CBenzBuilder :
    public ICarBuilder
{
public:
    CBenzBuilder(void);
    ~CBenzBuilder(void);
    void SetSequence(vector<string> *pSeq);
    CCarModel * GetCarModel();
private:
    CCarModel *m_pBenz;
};

BenzBuilder.cpp

#include <stdio.h>
#include "BenzBuilder.h"
#include "BenzModel.h"
CBenzBuilder::CBenzBuilder(void)
{
    m_pBenz = new CBenzModel();
}
CBenzBuilder::~CBenzBuilder(void)
{
    delete m_pBenz;
}
void CBenzBuilder::SetSequence(vector<string> *pSeq)
{
    m_pBenz->SetSequence(pSeq);
}
CCarModel * CBenzBuilder::GetCarModel()
{
    return m_pBenz;
}

BMWBuilder.h

#pragma once
#include "icarbuilder.h"
#include "CarModel.h"
#include <iostream>
#include <vector>
using std::string;
using std::vector;
class CBMWBuilder :
    public ICarBuilder
{
public:
    CBMWBuilder(void);
    ~CBMWBuilder(void);
    void SetSequence(vector<string> *pSeq);
    CCarModel * GetCarModel();
private:
    CCarModel *m_pBMW;
};

BMWBuilder.cpp

#include <stdio.h>
#include "BMWBuilder.h"
#include "BMWModel.h"
CBMWBuilder::CBMWBuilder(void)
{
    m_pBMW = new CBMWModel();
}
CBMWBuilder::~CBMWBuilder(void)
{
    delete m_pBMW;
}
void CBMWBuilder::SetSequence( vector<string> *pSeq )
{
    m_pBMW->SetSequence(pSeq);
}
CCarModel * CBMWBuilder::GetCarModel()
{
    return m_pBMW;
}

Director.h

#pragma once
#include "BenzModel.h"
#include "BMWModel.h"
#include "BenzBuilder.h"
#include "BMWBuilder.h"
#include <vector>
using std::vector;
class CDirector
{
public:
    CDirector(void);
    ~CDirector(void);
    CBenzModel * GetABenzModel();
    CBenzModel * GetBBenzModel();
    CBMWModel * GetCBMWModel();
    CBMWModel * GetDBMWModel();
private:
    vector<string> * m_pSeqence;
    CBenzBuilder * m_pBenzBuilder;
    CBMWBuilder * m_pBMWBuilder;
};

Director.cpp

#include <stdio.h>
#include "Director.h"
CDirector::CDirector(void)
{
    m_pBenzBuilder = new CBenzBuilder();
    m_pBMWBuilder = new CBMWBuilder();
    m_pSeqence = new vector<string>();
}
CDirector::~CDirector(void)
{
    delete m_pBenzBuilder;
    delete m_pBMWBuilder;
    delete m_pSeqence;
}
CBenzModel * CDirector::GetABenzModel()
{
    m_pSeqence->clear();
    m_pSeqence->push_back("start");
    m_pSeqence->push_back("stop");
    m_pBenzBuilder->SetSequence(m_pSeqence);
    return dynamic_cast<CBenzModel*>(m_pBenzBuilder->GetCarModel());
}
CBenzModel * CDirector::GetBBenzModel()
{
    m_pSeqence->clear();
    m_pSeqence->push_back("engine boom");//业务逻辑处理
    m_pSeqence->push_back("start");
    m_pSeqence->push_back("stop");
    m_pBenzBuilder->SetSequence(m_pSeqence);
    return dynamic_cast<CBenzModel*>(m_pBenzBuilder->GetCarModel());
}
CBMWModel * CDirector::GetCBMWModel()
{
    m_pSeqence->clear();
    m_pSeqence->push_back("alarm");//业务逻辑处理
    m_pSeqence->push_back("start");
    m_pSeqence->push_back("stop");
    m_pBMWBuilder->SetSequence(m_pSeqence);
    return static_cast<CBMWModel*>(m_pBMWBuilder->GetCarModel());
}
CBMWModel * CDirector::GetDBMWModel()
{
    m_pSeqence->clear();
    m_pSeqence->push_back("start");
    m_pBenzBuilder->SetSequence(m_pSeqence);
    return dynamic_cast<CBMWModel*>(m_pBMWBuilder->GetCarModel());
}

main.cpp

#include <stdio.h>
#include "CarModel.h"
#include "BenzModel.h"
#include "BMWModel.h"
#include "BenzBuilder.h"
#include "BMWBuilder.h"
#include "Director.h"
#include <vector>
#include <iostream>
using std::vector;
using std::string;
using std::cout;
using std::endl;

int main()
{
   cout << "----------生成奔驰模型----------" << endl;
   CBenzModel* pBenz = new CBenzModel();
   vector<string> seq;
   seq.push_back("engine boom");//客户要求run的时候先发动引擎
   seq.push_back("start");//启动起来
   seq.push_back("stop");//开了一段就停下来

   pBenz->SetSequence(&seq);
   pBenz->Run();
   delete pBenz;

//使用模式后,由benzBuilder和bmwBuilder来生成,并且使用同样的创建顺序。
   cout << "----------用同一个顺序,生成模型----------" << endl;
   vector<string> seq;
   seq.push_back("engine boom");
   seq.push_back("start");
   seq.push_back("stop");

   CBenzBuilder benzBuilder;
   benzBuilder.SetSequence(&seq);
   CBenzModel* pBenz = dynamic_cast<CBenzModel*>(benzBuilder.GetCarModel());
   pBenz->Run();

   CBMWBuilder bmwBuilder;
   bmwBuilder.SetSequence(&seq);
   CBMWModel* pBmw = dynamic_cast<CBMWModel*>(bmwBuilder.GetCarModel());
   pBenz->Run();


//使用指导者来封装创建的逻辑,把创建的顺序内聚在指导者类里面。
   cout << "----------批量生成模型----------" << endl;
   CDirector director;

   //1W辆A类型的奔驰车
   for (int i = 0; i < 2; i++)
      director.GetABenzModel()->Run();

   //100W辆B类型的奔驰车
   for (int i = 0; i < 2; i++)
      director.GetBBenzModel()->Run();

   //1000W辆C类型的宝马车
   for (int i = 0; i < 2; i++)
      director.GetCBMWModel()->Run();

   return 0;
}
----------用同一个顺序,生成模型----------
奔驰引擎声音是这样....
奔驰发动...
奔驰停车...
奔驰引擎声音是这样....
奔驰发动...
奔驰停车...
----------批量生成模型----------
奔驰发动...
奔驰停车...
奔驰发动...
奔驰停车...
奔驰引擎声音是这样....
奔驰发动...
奔驰停车...
奔驰引擎声音是这样....
奔驰发动...
奔驰停车...
宝马鸣笛
宝马发动...
宝马停车...
宝马鸣笛
宝马发动...
宝马停车...

代理模式

Provide a surrogate or placeholder for another object to control access to it.

为其他对象提供一种代理以控制对这个对象的访问。

代理模式

代理模式也叫做委托模式,它是一项基本设计技巧。许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应用中,代理模式可以提供非常好的访问控制。

● Subject抽象主题角色
抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。

● RealSubject具体主题角色
也叫做被委托角色、被代理角色,是业务逻辑的具体执行者。

● Proxy代理主题角色
也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。

代理模式的优点:

● 职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。

● 高扩展性
具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。

● 智能化
这在我们以上的讲解中还没有体现出来,不过在我们以下的动态代理章节中你就会看到代理的智能化有兴趣的读者也可以看看Struts是如何把表单元素映射到对象上的。

我相信第一次接触到代理模式的读者肯定很郁闷,为什么要用代理呀?

代理模式其实是功能业务分离的体现,职责清晰,功能实现后,由代理者进行业务处理或属性控制,并作为接口调用,比如:我想买车,我真正要做的是付钱换来车,但中间找车源,谈价钱等业务流程交给代理去做就ok了.

再比如我在公司上网,公司会强制我们使用公司的代理,当我点击浏览器发起网页请求时,公司代理会对网页进行业务处理(筛选过滤娱乐信息等),然后将代理后的结果发送给我们(如果无害则直接返给我们,如果有害则直接屏蔽)。

代理也是功能逻辑分离的意思,比如谷歌服务器提供了完全的功能,而每个公司有不同的业务逻辑(娱乐公司可以看娱乐新闻,互联网公司不允许看娱乐新闻),所以会有代理,同时代理也作为接口包装了功能然后供使用者调用。

总结来说,代理可以作为对功能的控制,如版本,名字,有效性等;也可以作为功能的接口被使用者调用。

一种代理的方式是继承功能类,另一种代理的方式是做成代理模板类。


//主题类
class Subject
{
public:
  virtual Subject()=0;
  virtual ~Subject()=0;
  virtual void Request()=0;//具体代理的任务
};

//真实主题类
class ConcreteSubject:public Subject
{
public:
  ConcreteSubject();
  ~ConcreteSubject();
  void Request();
};

//代理类
class Proxy:public Subject
{
public:
  Proxy();
  Proxy(Subject* _sub);
  ~Proxy();

  void Request()//实现对委托者的委托任务执行与补偿
  {
    bef();
    this->_sub->Request();
    end();
  }

  void bef()
  {}

  void end()
  {}

private:
  Subject* _sub;
};

原型模式

Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。


简单,太简单了!原型模式的核心是一个clone方法,通过该方法进行对象的拷贝。

当需要new一个对来象,但是对象需要调用的构造函数自比较复杂,构造函数中有大量的初始化语句,为了让客户与这知个复杂的new过程解耦就可以使用原型模式了。原型模式实际上就是用一个道clone函数将构造函数封装起来,方便客户去new一个对象。

批注:当你不知道怎么使用构造函数new一个对象时,选择一个已经实例化的对象复制一个同样的对象并返回,就完全不用考虑构造函数的参数了。

main.cpp

#include <iostream>
#include <string>
using namespace std;

class Prototype
{
private:
    string str;
public:
    Prototype(string s)
    {
        str = s;
    }
    Prototype()
    {
        str = "";
    }
    void show()
    {
        cout << str << endl;
    }
    virtual Prototype *clone() = 0;
};

class ConcretePrototype1 :public Prototype
{
public:
    ConcretePrototype1(string s) :Prototype(s)
    {}
    ConcretePrototype1(){}
    virtual Prototype *clone()
    {
        ConcretePrototype1 *p = new ConcretePrototype1();
        *p = *this;
        return p;
    }
};


class ConcretePrototype2 :public Prototype
{
public:
    ConcretePrototype2(string s) :Prototype(s)
    {}
    ConcretePrototype2(){}
    virtual Prototype *clone()
    {
        ConcretePrototype2 *p = new ConcretePrototype2();
        *p = *this;
        return p;
    }
};

int main()
{
    ConcretePrototype1 *test = new ConcretePrototype1("小李");
    ConcretePrototype2 *test2 = (ConcretePrototype2 *)test->clone();//不需要考虑构造函数的参数就new了一个。
    test->show();
    test2->show();
    return 0;
}
小李
小李

中介者模式

Define an object that encapsulates how a set of objects interact.Mediator promotes loose coupling by keeping objects from referring to each other explicitly,and it lets you vary their interaction independently.

用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

中介者模式
从类图中看,中介者模式由以下几部分组成:

  • Mediator 抽象中介者角色
    抽象中介者角色定义统一的接口,用于各同事角色之间的通信。
  • Concrete Mediator 具体中介者角色
    具体中介者角色通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。
  • Colleague 同事角色
    每一个同事角色都知道中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作。每个同事类的行为分为两种:一种是同事本身的行为,比如改变对象本身的状态,处理自己的行为等,这种行为叫做自发行为(Self-Method),与其他的同事类或中介者没有任何的依赖;第二种是必须依赖中介者才能完成的行为,叫做依赖方法(Dep-Method)。

中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。

中介者模式的优点
中介者模式的优点就是减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,当然同时也降低了类间的耦合。

中介者模式的缺点
中介者模式的缺点就是中介者会膨胀得很大,而且逻辑复杂,原本N个对象直接的相互依赖关系转换为中介者和同事类的依赖关系,同事类越多,中介者的逻辑就越复杂。

MVC框架
大家都应该使用过Struts,MVC框架,其中的C(Controller)就是一个中介者,叫做前端控制器(Front Controller),它的作用就是把M(Model,业务逻辑)和V(View,视图)隔离开,协调M和V协同工作,把M运行的结果和V代表的视图融合成一个前端可以展示的页面,减少M和V的依赖关系。MVC框架已经成为一个非常流行、成熟的开发框架,这也是中介者模式的优点的一个体现。


main.cpp

#include <iostream>
#include <string>
using namespace std;

class Colleague;

class Mediator {
public:
    virtual void Send(string message, Colleague* colleague) = 0;
    virtual ~Mediator() {}
};

class Colleague {
protected:
    Mediator* mediator;
public:
    Colleague(Mediator* m) { mediator = m; }
};

class ConcreteColleague1 : public Colleague {
public:
    ConcreteColleague1(Mediator* m) : Colleague(m) {}
    void Send(string message) {
        mediator->Send(message, this);
    }
    void Notify(string message) {
        cout << "ConcreteColleague1 received: " << message << endl;
    }
};

class ConcreteColleague2 : public Colleague {
public:
    ConcreteColleague2(Mediator* m) : Colleague(m) {}
    void Send(string message) {
        mediator->Send(message, this);
    }
    void Notify(string message) {
        cout << "ConcreteColleague2 received: " << message << endl;
    }
};

class ConcreteMediator : public Mediator {
private:
    ConcreteColleague1* c1;
    ConcreteColleague2* c2;
public:
    void set(ConcreteColleague1* c) { c1 = c; }
    void set(ConcreteColleague2* c) { c2 = c; }
    //通过colleague传入对象进行判断,然后选择行为。
    void Send(string message, Colleague* colleague) {
        if (colleague == c1) c2->Notify(message);
        else c1->Notify(message);
    }
};

int main() {
    //创建一个中介
    ConcreteMediator* m = new ConcreteMediator();

    //同事向中介注册,并返回绑定信息
    ConcreteColleague1* c1 = new ConcreteColleague1(m);
    ConcreteColleague2* c2 = new ConcreteColleague2(m);

    //中介根据绑定信息决定是否接受同事的注册
    //为什么同事类要使用构造函数注入中介者,而中介者使用getter/setter方式注入同事类呢?这是因为同事类必须有中介者,而中介者却可以只有部分同事类。
    m->set(c1);
    m->set(c2);

    //c1向总线m发送信息,总线收到后判断对象类型,再调用c1实现的方法Notify()
    c1->Send("Hello");   // ConcreteColleague2 received: Hello
    c2->Send("World");  // ConcreteColleague1 received: World

    delete m;
    delete c1;
    delete c2;

    return 0;
}
g++ main.cpp
./a.out
ConcreteColleague2 received: Hello
ConcreteColleague1 received: World

批注:看上去和观察者模式很像啊,突然觉得没有那么多设计模式,都是变体。

命令模式

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

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

批注:命令模式和建造者模式很像,最小化实现功能单元,然后通过一个对象组合这些最小化单元,供客户端调用。


main(),客户

CInvoker,命令接收者,如项目经理

IGroup,执行者接口

CRequirementGroup,实际执行者之一

CPageGroup,实际执行者之二

CCodePage,实际执行者之三

ICommand,命令接口

CAddRequirementCommand,Execute函数,将调用CRequirementGroup的多个命令。来组合执行用户发出的命令。

CDeletePageCommand,同上

... ... 其它命令。

说明:客户只需要知道向Invoker发出命令(多个命令),而不是将命令直接传达给具体的执行者。当然,客户是需要知道都有什么命令的。

注意:客户只发命令,不需要知道由谁来执行和怎么执行,体现出高内聚的特点。用户在发出命令后,是允许撤回的,所以可以增加一个命令“Undo ”,Undo是状态的变更。

旅行社项目开发过程类图

Invoker.h

#pragma once
#include "ICommand.h"
class CInvoker
{
public:
    CInvoker(void);
    ~CInvoker(void);
    void SetCommand(ICommand *pcommand);
    void Action();
private:
    ICommand *m_pCommand;
};

Invoker.cpp

#include <stdio.h>
#include "Invoker.h"
CInvoker::CInvoker(void)
{
}
CInvoker::~CInvoker(void)
{
}
void CInvoker::SetCommand( ICommand *pcommand )
{
    this->m_pCommand = pcommand;
}
void CInvoker::Action()
{
    this->m_pCommand->Execute();
}

IGroup.h

#pragma once
class IGroup
{
public:
    IGroup(void)
    {
    }
    virtual ~IGroup(void)
    {
    }
    virtual void Find() = 0;
    virtual void Add() = 0;
    virtual void Delete() = 0;
    virtual void Change() = 0;
    virtual void Plan() = 0;
};

RequirementGroup.h

#pragma once
#include "igroup.h"
class CRequirementGroup :
    public IGroup
{
public:
    CRequirementGroup(void);
    ~CRequirementGroup(void);
    void Find();
    void Add();
    void Delete();
    void Change();
    void Plan();
};

RequirementGroup.cpp

#include <stdio.h>
#include "RequirementGroup.h"
#include <iostream>
using std::cout;
using std::endl;
CRequirementGroup::CRequirementGroup(void)
{
}
CRequirementGroup::~CRequirementGroup(void)
{
}
void CRequirementGroup::Find()
{
    cout << "找到需求组..." << endl;
}
void CRequirementGroup::Add()
{
    cout << "客户要求增加一项需求..." << endl;
}
void CRequirementGroup::Delete()
{
    cout << "要求删除一项需求..." << endl;
}
void CRequirementGroup::Change()
{
    cout << "客户要求修改一项需求..." << endl;
}
void CRequirementGroup::Plan()
{
    cout << "客户要求需求变更计划..." << endl;
}

PageGroup.h

#pragma once
#include "igroup.h"
class CPageGroup :
    public IGroup
{
public:
    CPageGroup(void);
    ~CPageGroup(void);
    void Find();
    void Add();
    void Delete();
    void Change();
    void Plan();
};

PageGroup.cpp

#include <stdio.h>
#include "PageGroup.h"
#include <iostream>
using std::cout;
using std::endl;
CPageGroup::CPageGroup(void)
{
}
CPageGroup::~CPageGroup(void)
{
}
void CPageGroup::Find()
{
    cout << "找到美工组..." << endl;
}
void CPageGroup::Add()
{
    cout << "客户要求增加一个页面..." << endl;
}
void CPageGroup::Delete()
{
    cout << "客户要求删除一个页面..." << endl;
}
void CPageGroup::Change()
{
    cout << "客户要求修改一个页面..." << endl;
}
void CPageGroup::Plan()
{
    cout << "客户要求页面变更计划..." << endl;
}

CodeGroup.h

#pragma once
#include "igroup.h"
class CCodeGroup :
    public IGroup
{
public:
    CCodeGroup(void);
    ~CCodeGroup(void);
    void Find();
    void Add();
    void Delete();
    void Change();
    void Plan();
};

CodeGroup.cpp

#include <stdio.h>
#include "CodeGroup.h"
#include <iostream>
using std::cout;
using std::endl;
CCodeGroup::CCodeGroup(void)
{
}
CCodeGroup::~CCodeGroup(void)
{
}
void CCodeGroup::Find()
{
    cout << "找到代码组..." << endl;
}
void CCodeGroup::Add()
{
    cout << "客户要求增加一项功能..." << endl;
}
void CCodeGroup::Delete()
{
    cout << "客户要求删除一项功能..." << endl;
}
void CCodeGroup::Change()
{
    cout << "客户要求修改一项功能..." << endl;
}
void CCodeGroup::Plan()
{
    cout << "客户要求代码变更计划..." << endl;
}

ICommand.h

#pragma once
#include "RequirementGroup.h"
#include "PageGroup.h"
#include "CodeGroup.h"
class ICommand
{
public:
    ICommand(void)
    {
        m_prg = new CRequirementGroup();
        m_ppg = new CPageGroup();
        m_pcg = new CCodeGroup();
    }
    virtual ~ICommand(void)
    {
        delete m_prg;
        delete m_ppg;
        delete m_pcg;
    }
    virtual void Execute() = 0;
protected:
    CRequirementGroup *m_prg;
    CPageGroup *m_ppg;
    CCodeGroup *m_pcg;
};

AddRequirementCommand.h

#pragma once
#include "icommand.h"
class CAddRequirementCommand :
    public ICommand
{
public:
    CAddRequirementCommand(void);
    ~CAddRequirementCommand(void);
    void Execute();
};

AddRequirementCommand.cpp

#include <stdio.h>
#include "AddRequirementCommand.h"
CAddRequirementCommand::CAddRequirementCommand(void)
{
}
CAddRequirementCommand::~CAddRequirementCommand(void)
{
}
void CAddRequirementCommand::Execute()
{
    //执行增另一项需求的命令
    this->ICommand::m_prg->Find();

    //增加一份需求
    this->ICommand::m_prg->Add();

    //给出计划
    this->ICommand::m_prg->Plan();
}

DeletePageCommand.h

#pragma once
#include "icommand.h"
class CDeletePageCommand :
    public ICommand
{
public:
    CDeletePageCommand(void);
    ~CDeletePageCommand(void);
    void Execute();
};

DeletePageCommand.cpp

#include <stdio.h>
#include "DeletePageCommand.h"
CDeletePageCommand::CDeletePageCommand(void)
{
}
CDeletePageCommand::~CDeletePageCommand(void)
{
}
void CDeletePageCommand::Execute()
{
    //执行增另一项需求的命令
    this->ICommand::m_ppg->Find();

    //增加一份需求
    this->ICommand::m_ppg->Delete();

    //给出计划
    this->ICommand::m_ppg->Plan();
}

Command.cpp

#include <stdio.h>
#include "IGroup.h"
#include "CodeGroup.h"
#include "PageGroup.h"
#include "RequirementGroup.h"
#include "Invoker.h"
#include "AddRequirementCommand.h"
#include "DeletePageCommand.h"
#include <iostream>
using std::cout;
using std::endl;

void DoIt()
{
    cout << "----------客户想增加一个需求----------" << endl;
    IGroup *rg = new CRequirementGroup();
    rg->Find();
    rg->Add();
    rg->Plan();
    delete rg;
    cout << endl;

    cout << "----------客户又想修改一个页面----------" << endl;
    IGroup *pg = new CPageGroup();
    pg->Find();
    pg->Add();
    pg->Plan();
    delete pg;
    cout << endl;

    cout << "----------客户又想删除一个功能----------" << endl;
    IGroup *cg = new CCodeGroup();
    cg->Find();
    cg->Add();
    cg->Plan();
    delete cg;
    cout << endl;
}

void DoNew()
{
    cout << "----------客户觉得烦了,希望只找一个人,并告诉他要做什么----------" << endl;
    cout << "----------客户要求增加一项需求----------" << endl;
    CInvoker gary;
    ICommand *pcommand = new CAddRequirementCommand();
    gary.SetCommand(pcommand);
    gary.Action();
    delete pcommand;
    cout << endl;

    //客户想要改动只需要找CInvoker就可以了。
    cout << "----------客户要求删除一个页面----------" << endl;
    CInvoker ricky;
    ICommand *pcommand2 = new CDeletePageCommand();
    ricky.SetCommand(pcommand2);
    ricky.Action();
    delete pcommand2;
    cout << endl;
}

int main()
{
    //客户原来的运行流程
    DoIt();

    //客户觉得麻烦了,每次改动都要找不同的组,谈不同的事
    //客户只想找一个人,告诉他要做什么就可以,不想关心由哪几个组来做和怎么做
    DoNew();

    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
    _CrtDumpMemoryLeaks();
    return 0;
}
----------客户想增加一个需求----------
找到需求组...
客户要求增加一项需求...
客户要求需求变更计划...
----------客户又想修改一个页面---------
找到美工组...
客户要求增加一个页面...
客户要求页面变更计划...
----------客户又想删除一个功能----------
找到代码组...
客户要求增加一项功能...
客户要求代码变更计划...
----------客户觉得烦了,希望只找一个人,并告诉他要做什么----------
----------客户要求增加一项需求----------
找到需求组...
客户要求增加一项需求...
客户要求需求变更计划...
----------客户要求删除一个页面----------
找到美工组...
客户要求删除一个页面...
客户要求页面变更计划...

责任链模式

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.

使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。

缺点:1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。

使用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。


main(),客户

IWomen,发出请求者接口

CWomen,请求者实现类

CHandler,处理请求抽象类

CFather,处理请求实现类,责任链之一

CHusband,处理请求实现类,责任链之二

CSon,处理请求实现类,责任链之三

说明:CHandler抽象类负责聚合责任链之中的其它处理对象,用SetNext来建立这个责任链。HandleMessage在处理请求时,会判断是否是自己要处理的请求,如果是则直接处理。如果不是,则查找下一个责任链上的处理对象,找到了则由下一个处理。

妇女“三从”类图

IWomen.h

#pragma once
#include <iostream>
using std::string;
class IWomen
{
public:
    IWomen(void)
    {
    }
    virtual ~IWomen(void)
    {
    }
    virtual int GetType() = 0;
    virtual string GetRequest() = 0;
};

Women.h

#pragma once
#include "iwomen.h"
#include <iostream>
using std::string;
class CWomen :
    public IWomen
{
public:
    CWomen(int _type, string _request);
    ~CWomen(void);
    int GetType();
    string GetRequest();
private:
    int m_type;
    string m_request;
};

Women.cpp

#include <stdio.h>
#include "Women.h"
CWomen::CWomen( int _type, string _request )
{
    this->m_type = _type;
    switch (this->m_type)
    {
    case 1:
        this->m_request.append("女儿的请求是:");
        this->m_request.append(_request);
        break;
    case 2:
        this->m_request.append("妻子的请求是:");
        this->m_request.append(_request);
        break;
    case 3:
        this->m_request.append("母亲的请求是:");
        this->m_request.append(_request);
        break;
    }
}
CWomen::~CWomen(void)
{
}
int CWomen::GetType()
{
    return m_type;
}
string CWomen::GetRequest()
{
    return m_request;
}

Handler.h

#pragma once
#include "IWomen.h"
class CHandler
{
public:
    CHandler(int _level);
    virtual ~CHandler(void);
    void HandleMessage(IWomen *pwomen);
    void SetNext(CHandler *phandler);
    virtual void Response(IWomen *pwomen) = 0;
private:
    int m_level;
    CHandler *m_pNextHandler;
};

Handler.cpp

#include <stdio.h>
#include "Handler.h"
#include <iostream>
using std::cout;
using std::endl;
CHandler::CHandler(int _level ) : m_level(_level)
{
    m_pNextHandler = NULL;
}
CHandler::~CHandler(void)
{
}
void CHandler::HandleMessage( IWomen *pwomen )
{
    if (pwomen->GetType() == this->m_level)
    {
        this->Response(pwomen);
    }
    else
    {
        if(this->m_pNextHandler != NULL)
            this->m_pNextHandler->HandleMessage(pwomen);
        else
            cout << "----------没地方请示了,不做处理!----------" << endl;
    }
}
void CHandler::SetNext( CHandler *phandler )
{
    m_pNextHandler = phandler;
}

Father.h

#pragma once
#include "handler.h"
#include "IWomen.h"
class CFather :
    public CHandler
{
public:
    CFather(void);
    ~CFather(void);
    void Response(IWomen *pwomen);
};

Father.cpp

#include <stdio.h>
#include "Father.h"
#include <iostream>
using std::cout;
using std::endl;
CFather::CFather(void) : CHandler(1)
{
}
CFather::~CFather(void)
{
}
void CFather::Response( IWomen *pwomen )
{
    cout << "女儿向父亲请示:" << endl;
    cout << pwomen->GetRequest().c_str() << endl;
    cout << "父亲的答复是:同意" << endl;
}

Husband.h

#pragma once
#include "handler.h"
#include "IWomen.h"
class CHusband :
    public CHandler
{
public:
    CHusband(void);
    ~CHusband(void);
    void Response(IWomen *pwomen);
};

Husband.cpp

#include <stdio.h>
#include "Husband.h"
#include <iostream>
using std::cout;
using std::endl;
CHusband::CHusband(void) : CHandler(2)
{
}
CHusband::~CHusband(void)
{
}
void CHusband::Response( IWomen *pwomen )
{
    cout << "妻子向丈夫请示:" << endl;
    cout << pwomen->GetRequest().c_str() << endl;
    cout << "丈夫的答复是:同意" << endl;
}

Son.h

#pragma once
#include "handler.h"
#include "IWomen.h"
class CSon :
    public CHandler
{
public:
    CSon(void);
    ~CSon(void);
    void Response(IWomen *pwomen);
};

Son.cpp

#include <stdio.h>
#include "Son.h"
#include <iostream>
using std::cout;
using std::endl;
CSon::CSon(void) : CHandler(3)
{
}
CSon::~CSon(void)
{
}
void CSon::Response( IWomen *pwomen )
{
    cout << "母亲向儿子请示:" << endl;
    cout << pwomen->GetRequest().c_str() << endl;
    cout << "儿子的答复是:同意" << endl;
}

ChainofResponsibility.cpp

#include <stdio.h>
#include "IWomen.h"
#include "Women.h"
#include "Handler.h"
#include "Father.h"
#include "Husband.h"
#include "Son.h"
#include <iostream>
using std::cout;
using std::endl;
void DoIt()
{
   //cout << "----------原来的处理方式----------" << endl;
   INormalWomen* pwomen = new CNormalWomen(1, "我要出去逛街");
   INormalHandler* pfather = new CNormalFather();
   INormalHandler* phusband = new CNormalHusband();
   INormalHandler* pson = new CNormalSon();
   If (pwomen->GetType() == 1)
   //{
   //   cout << "女儿向父亲请示:" << endl;
   //   pfather->HandleMessage(pwomen);
   //}
   //else if (pwomen->GetType() == 2)
   //{
   //   cout << "妻子向丈夫请示:" << endl;
   //   phusband->HandleMessage(pwomen);
   //}
   //else if (pwomen->GetType() == 3)
   //{
   //   cout << "母亲向儿子请示:" << endl;
   //   pson->HandleMessage(pwomen);
   //}
   //else
   //{
   //   //什么也不做
   //}
   //delete pwomen;
   //delete pfather;
   //delete phusband;
   //delete pson;
}
void DoNew()
{
   cout << "----------使用模式后的处理方式----------" << endl;

   IWomen* pwomen1 = new CWomen(1, "我要出去逛街");
   IWomen* pwomen2 = new CWomen(2, "我要出去吃饭");
   IWomen* pwomen3 = new CWomen(3, "我也要出去吃饭");
   IWomen* pwomen4 = new CWomen(4, "我也要出去逛街");

   CHandler* pfather = new CFather();
   CHandler* phusband = new CHusband();
   CHandler* pson = new CSon();

   pfather->SetNext(phusband);
   phusband->SetNext(pson);

   pfather->HandleMessage(pwomen1);
   pfather->HandleMessage(pwomen2);
   pfather->HandleMessage(pwomen3);
   pfather->HandleMessage(pwomen4);

   delete pfather;
   delete phusband;
   delete pson;
   delete pwomen1;
   delete pwomen2;
   delete pwomen3;
   delete pwomen4;
}
int main()
{
   //反面
   DoIt();
   //要实现逻辑判断,即女性的请求先发送到父亲类,父亲类一看是自己要处理的,就回应进行处理。如果女儿已经出嫁了,那就把这个请求转发到女婿类来处理。依此类推,形成了一个责任链。
   DoNew();
   return 0;
}
----------使用模式后的处理方式----------
女儿向父亲请示:
女儿的请求是:我要出去逛街
父亲的答复是:同意
妻子向丈夫请示:
妻子的请求是:我要出去吃饭
丈夫的答复是:同意
母亲向儿子请示:
母亲的请求是:我也要出去吃饭
儿子的答复是:同意
----------没地方请示了,不做处理!----------

装饰模式

Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂。

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。


main(),老爸

ISchoolReport,成绩单接口

CFourthGradeSchoolReport,四年级成绩单

ReportDecorator,成绩单装饰器基类

HighScoreDecorator,最高分装饰器

SortDecorator,班级排名装饰器

说明:对“四年级成绩单”进行装饰,ReportDecorator必然有一个private变量指向ISchoolReport。

成绩单类图

ISchoolReport.h

#pragma once
#include <iostream>
using std::string;
class ISchoolReport
{
public:
    ISchoolReport(void)
    {
    }
    virtual ~ISchoolReport(void)
    {
    }
    virtual void Report() = 0;
    virtual void Sign(string name) = 0;
};

FouthGradeSchoolReport.h

#pragma once
#include "ischoolreport.h"
class CFouthGradeSchoolReport :
    public ISchoolReport
{
public:
    CFouthGradeSchoolReport(void);
    ~CFouthGradeSchoolReport(void);
    void Report();
    void Sign(string name);
};

FouthGradeSchoolReport.cpp

#include <stdio.h>
#include "FouthGradeSchoolReport.h"
#include <iostream>
using std::cout;
using std::endl;
using std::string;
CFouthGradeSchoolReport::CFouthGradeSchoolReport(void)
{
}
CFouthGradeSchoolReport::~CFouthGradeSchoolReport(void)
{
}
void CFouthGradeSchoolReport::Report()
{
    cout << "尊敬的XXX家长:" << endl;
    cout << "......" << endl;
    cout << "语文62  数学65  体育98  自然63" << endl;
    cout << "......" << endl;
    cout << "                家长签名:" << endl;
}
void CFouthGradeSchoolReport::Sign(string name)
{
    cout << "家长签名为:" << name.c_str() << endl;
}

ReportDecorator.h

#pragma once
#include "ischoolreport.h"
class CReportDecorator :
    public ISchoolReport
{
public:
    CReportDecorator(ISchoolReport *psr);
    virtual ~CReportDecorator(void);
    void Report();
    void Sign(string name);
private:
    ISchoolReport *m_pSchoolReport;
};

ReportDecorator.cpp

#include <stdio.h>
#include "ReportDecorator.h"
#include <iostream>
using std::string;
CReportDecorator::CReportDecorator(ISchoolReport *psr)
{
    this->m_pSchoolReport = psr;
}
CReportDecorator::~CReportDecorator(void)
{
}
void CReportDecorator::Report()
{
    this->m_pSchoolReport->Report();
}
void CReportDecorator::Sign( string name )
{
    this->m_pSchoolReport->Sign(name);
}

HighScoreDecorator.h

#pragma once
#include "reportdecorator.h"
#include "ISchoolReport.h"
class CHighScoreDecorator :
    public CReportDecorator
{
public:
    CHighScoreDecorator(ISchoolReport *psr);
    ~CHighScoreDecorator(void);
    void Report();
private:
    void ReportHighScore();
};

HighScoreDecorator.cpp

#include <stdio.h>
#include "HighScoreDecorator.h"
#include <iostream>
using std::cout;
using std::endl;
CHighScoreDecorator::CHighScoreDecorator( ISchoolReport *psr ) : CReportDecorator(psr)
{
}
CHighScoreDecorator::~CHighScoreDecorator(void)
{
}
void CHighScoreDecorator::Report()
{
    this->ReportHighScore();
    this->CReportDecorator::Report();
}
void CHighScoreDecorator::ReportHighScore()
{
    cout << "这次考试语文最高是75, 数学是78, 自然是80" << endl;
}

SortDecorator.h

#pragma once
#include "reportdecorator.h"
#include "ISchoolReport.h"
class CSortDecorator :
    public CReportDecorator
{
public:
    CSortDecorator(ISchoolReport *psr);
    ~CSortDecorator(void);
    void Report();
private:
    void ReportSort();
};

SortDecorator.cpp

#include <stdio.h>
#include "SortDecorator.h"
#include <iostream>
using std::cout;
using std::endl;
CSortDecorator::CSortDecorator( ISchoolReport *psr ) : CReportDecorator(psr)
{
}
CSortDecorator::~CSortDecorator(void)
{
}
void CSortDecorator::ReportSort()
{
    cout << "我是排名第38名..." << endl;
}
void CSortDecorator::Report()
{
    this->CReportDecorator::Report();
    this->ReportSort();
}

main.cpp

#include <stdio.h>
#include "ISchoolReport.h"
#include "FouthGradeSchoolReport.h"
#include "FouthGradeSchoolReport.h"
#include "HighScoreDecorator.h"
#include "SortDecorator.h"
#include <iostream>
using std::cout;
using std::endl;
void DoIt()
{
   ISchoolReport* psr = new CFouthGradeSchoolReport();
   psr->Report();//看成绩单
   psr->Sign("老三");//很开心,就签字了
   delete psr;
}
void DoNew()
{
   cout << "----------分部分进行装饰----------" << endl;
   ISchoolReport* psr = new CFouthGradeSchoolReport();//原装成绩单
   //
   ISchoolReport* pssr = new CSortDecorator(psr);//又加了成绩排名的说明
   ISchoolReport* phsr = new CHighScoreDecorator(pssr);//加了最高分说明的成绩单
   phsr->Report();//看成绩单
   phsr->Sign("老三");//很开心,就签字了

   //先装饰哪个不重要,顺序已经在装饰内部确定好,但一定要调用最后一个装饰器的接口。
   ISchoolReport *phsr = new CHighScoreDecorator(psr);//加了最高分说明的成绩单
   ISchoolReport *pssr = new CSortDecorator(phsr);//又加了成绩排名的说明
   //pssr->Report();//看成绩单
   //pssr->Sign("老三");//很开心,就签字了

   delete pssr;
   delete phsr;
   delete psr;
}
int main()
{
   //在装饰之前,可以用继承的办法,来进行简单的修饰
   DoIt();

   //但如果需要修饰的项目太多呢?或者装饰的项目不是固定的,继承显然会变得更复杂
   DoNew();

   return 0;
}
尊敬的XXX家长:
......
语文62  数学65  体育98  自然63
......
家长签名:
家长签名为:老三
----------分部分进行装饰----------
这次考试语文最高是75, 数学是78, 自然是80
尊敬的XXX家长:
......
语文62  数学65  体育98  自然63
......
家长签名:
我是排名第38名...
家长签名为:老三

策略模式

Define a family of algorithms,encapsulate each one,and make them interchangeable.

定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。

这个定义是非常明确、清晰的,“定义一组算法”,看看我们的三个计谋是不是三个算法?“将每个算法都封装起来”,封装类Context不就是这个作用吗?“使它们可以互换”当然可以互换了,都实现是相同的接口,那当然可以相互转化了。

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。

缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。


main(),赵云

CContext,锦囊

IStrategy,策略接口

CBackDoor,策略之一

CGivenGreenLight,策略之二

CBlockEnemy,策略之三

说明:一个策略放到一个锦囊里。当用的时候,找到这个锦囊,从锦囊里拿出策略来使用。

注意:锦囊只是简单的装载和调用策略,锦囊里没有逻辑。策略会有更大的自主权,运行更多的逻辑。
注意:没有#include "IStrategy.h"可以自建一个IStrategy.h,包含#include "stdio.h即可。

策略模式

IStrategy.h

#pragma once

class IStrategy
{
public:
    IStrategy(void){};
    virtual ~IStrategy(void){};
    virtual void Operate(void) = 0;
};

Context.h

#pragma once
#include "IStrategy.h"
class CContext
{
public:
    CContext(IStrategy *pStrategy);
    ~CContext(void);
    void Operate(void);
private:
    IStrategy *m_pStrategy;
};

Context.cpp

#include <stdio.h>
#include "Context.h"
CContext::CContext(IStrategy *pStrategy)
{
    this->m_pStrategy = pStrategy;
}
CContext::~CContext(void)
{
    delete this->m_pStrategy;
}
void CContext::Operate(void)
{
    this->m_pStrategy->Operate();
}

BackDoor.h

#pragma once
#include "istrategy.h"
class CBackDoor :
    public IStrategy
{
public:
    CBackDoor(void);
    ~CBackDoor(void);
    void Operate(void);
};

BackDoor.cpp

#include <stdio.h>
#include "BackDoor.h"
#include <iostream>
using std::cout;
using std::endl;
CBackDoor::CBackDoor(void)
{
}
CBackDoor::~CBackDoor(void)
{
}
void CBackDoor::Operate(void)
{
    cout << "找乔国老帮忙,让吴国太给孙权施加压力" << endl;
}

GivenGreenLight.h

#pragma once
#include "istrategy.h"
class CGivenGreenLight :
    public IStrategy
{
public:
    CGivenGreenLight(void);
    ~CGivenGreenLight(void);
    void Operate(void);
};

GivenGreenList.cpp

#include <stdio.h>
#include "GivenGreenLight.h"
#include <iostream>
using std::cout;
using std::endl;
CGivenGreenLight::CGivenGreenLight(void)
{
}
CGivenGreenLight::~CGivenGreenLight(void)
{
}
void CGivenGreenLight::Operate(void)
{
    cout << "求吴国太开个绿灯,放行!" << endl;
}

BlockEnemy.h

#pragma once
#include "istrategy.h"
class CBlockEnemy :
    public IStrategy
{
public:
    CBlockEnemy(void);
    ~CBlockEnemy(void);
    void Operate(void);
};

BlockEnemy.cpp

#include <stdio.h>
#include "BlockEnemy.h"
#include <iostream>
using std::cout;
using std::endl;
CBlockEnemy::CBlockEnemy(void)
{
}
CBlockEnemy::~CBlockEnemy(void)
{
}
void CBlockEnemy::Operate()
{
    cout << "孙夫人断后,挡住追兵" << endl;
}

main.cpp

#include <stdio.h>
#include "Context.h"
#include "BackDoor.h"
#include "GivenGreenLight.h"
#include "BlockEnemy.h"
#include <iostream>
using std::cout;
using std::endl;
int main()
{
    CContext *pContext;

    cout << "\14\n\n\n\n\17" << endl;
    cout << "----------刚刚到吴国的时候拆第一个----------" << endl;
    pContext = new CContext(new CBackDoor());
    pContext->Operate();
    delete pContext;

    cout << "\14\n\n\n\n\17" << endl;
    cout << "----------刘备乐不思蜀了,拆第二个了----------" << endl;
    pContext = new CContext(new CGivenGreenLight());
    pContext->Operate();
    delete pContext;

    cout << "\14\n\n\n\n\17" << endl;
    cout << "----------孙权的小兵追了,咋办?拆第三个----------" << endl;
    pContext = new CContext(new CBlockEnemy());
    pContext->Operate();
    delete pContext;

    return 0;
}

----------刚刚到吴国的时候拆第一个----------
找乔国老帮忙,让吴国太给孙权施加压力

----------刘备乐不思蜀了,拆第二个了----------
求吴国太开个绿灯,放行!

----------孙权的小兵追了,咋办?拆第三个----------
孙夫人断后,挡住追兵

适配器模式

Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。

优点: 1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。

缺点: 1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

使用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

批注:适配器相当于转换接头,如投影仪的接口是DB9,电脑的接口是HDMI,因此使用DB9转HDMI转换器就可以使投影仪和电脑一起工作了!
适配器起到了解析作用,将一种形式的数据结构解析为另一种形式的数据结构。

适配器的现象是:适配器class B fun(class A),
输入类型A对象,返回等价的类型B对象.
还可以是fidl适配器,fidl作为中间语言,可以将输入的其他语言/接口(如java)转化为另一种语言/接口(如C++)。
fidl还可以转化其他的东西.


main(),主程序

IUserInfo,本系统内接口

CUserInfo,本系统内实现类

IOuterUser,外系统接口

COuterUser,外系统实现类

COuterUserInfo,本系统内适配类

说明:COuterUserInfo实现IUserInfo接口,将外部系统实现类COuterUser转换成本系统内的接口IUserInfo。使用外部数据跟使用本系统内部数据一样。

注意:COuterUserInfo继承了IUserInfo,如果同时继承了COuterUser则是类适配器。如果COuterUserInfo只是使用了COuterUser则是对象适配器。

批注:本公司的人员信息管理系统和外聘人员的信息管理系统不一样,因此使用适配器模式将外聘人员信息解析成我们公司的人员管理信息进行统一储存管理。
外调人员中转处理

IUserInfo.h

#pragma once
#include <iostream>
using std::string;
class IUserInfo
{
public:
   IUserInfo(void)
   {
   }
   virtual ~IUserInfo(void)
   {
   }
   virtual string GetUserName() = 0;
   virtual string GetHomeAddress() = 0;
   virtual string GetMobileNumber() = 0;
   virtual string GetOfficeTelNumber() = 0;
   virtual string GetJobPosition() = 0;
   virtual string GetHomeTelNumber() = 0;
};

UserInfo.h

#pragma once
#include "iuserinfo.h"
#include <iostream>
using std::string;
class CUserInfo :
   public IUserInfo
{
public:
   CUserInfo(void);
   ~CUserInfo(void);
   string GetUserName();
   string GetHomeAddress();
   string GetMobileNumber();
   string GetOfficeTelNumber();
   string GetJobPosition();
   string GetHomeTelNumber();
};

UserInfo.cpp

#include <stdio.h>
#include "UserInfo.h"
#include <iostream>
using std::cout;
using std::endl;
using std::string;
CUserInfo::CUserInfo(void)
{
}
CUserInfo::~CUserInfo(void)
{
}
string CUserInfo::GetUserName()
{
   cout << "姓名叫做..." << endl;
   return "0";
}
string CUserInfo::GetHomeAddress()
{
   cout << "这里是员工的家庭地址..." << endl;
   return "0";
}
string CUserInfo::GetMobileNumber()
{
   cout << "这个人的手机号码是0000..." << endl;
   return "0";
}
string CUserInfo::GetOfficeTelNumber()
{
   cout << "办公室电话是..." << endl;
   return "0";
}
string CUserInfo::GetJobPosition()
{
   cout << "这个人的职位是BOSS..." << endl;
   return "0";
}
string CUserInfo::GetHomeTelNumber()
{
   cout << "员工的家庭电话是..." << endl;
   return "0";
}

IOuterUser.h

#pragma once
#include "OuterUserBaseInfo.h"
#include "OuterUserHomeInfo.h"
#include "OuterUserOfficeInfo.h"
class IOuterUser
{
public:
   IOuterUser(void)
   {
   }
   ~IOuterUser(void)
   {
   }
   COuterUserBaseInfo* GetUserBaseInfo() {};
   COuterUserHomeInfo* GetUserHomeInfo() {};
   COuterUserOfficeInfo* GetUserOfficeInfo() {};
};

COuterUser.h

#pragma once
#include "OuterUserBaseInfo.h"
#include "OuterUserHomeInfo.h"
#include "OuterUserOfficeInfo.h"
class COuterUser
{
public:
   COuterUser(void);
   ~COuterUser(void);
   COuterUserBaseInfo* GetUserBaseInfo();
   COuterUserHomeInfo* GetUserHomeInfo();
   COuterUserOfficeInfo* GetUserOfficeInfo();
};

COuterUser.cpp

#include <stdio.h>
#include "COuterUser.h"
#include "OuterUserBaseInfo.h"
#include "OuterUserHomeInfo.h"
#include "OuterUserOfficeInfo.h"
COuterUser::COuterUser(void)
{
}
COuterUser::~COuterUser(void)
{
}
COuterUserBaseInfo* COuterUser::GetUserBaseInfo()
{
   return new COuterUserBaseInfo();
}
COuterUserHomeInfo* COuterUser::GetUserHomeInfo()
{
   return new COuterUserHomeInfo();
}
COuterUserOfficeInfo* COuterUser::GetUserOfficeInfo()
{
   return new COuterUserOfficeInfo();
}

OuterUserBaseInfo.h

#pragma once
#include <iostream>
using std::cout;
using std::endl;
using std::string;
class COuterUserBaseInfo
{
public:
   COuterUserBaseInfo(void)
   {
   }
   ~COuterUserBaseInfo(void)
   {
   }
   string GetUserName()
   {
      cout << "姓名叫做..." << endl;
      return "0";
   }
   string GetMobileNumber()
   {
      cout << "这个人的手机号码是0001..." << endl;
      return "0";
   }
};

OuterUserHomeInfo.h

#pragma once
#include <iostream>
using std::cout;
using std::endl;
using std::string;
class COuterUserHomeInfo
{
public:
   COuterUserHomeInfo(void)
   {
   }
   ~COuterUserHomeInfo(void)
   {
   }
   string GetHomeAddress()
   {
      cout << "这里是员工的家庭地址..." << endl;
      return "0";
   }
   string GetHomeTelNumber()
   {
      cout << "员工的家庭电话是..." << endl;
      return "0";
   }
};

OuterUserOfficeInfo.h

#pragma once
#include <iostream>
using std::cout;
using std::endl;
using std::string;
class COuterUserOfficeInfo
{
public:
   COuterUserOfficeInfo(void)
   {
   }
   ~COuterUserOfficeInfo(void)
   {
   }
   string GetOfficeTelNumber()
   {
      cout << "办公室电话是..." << endl;
      return "0";
   }
   string GetJobPosition()
   {
      cout << "这个人的职位是BOSS..." << endl;
      return "0";
   }
};

OuterUserInfo.h

#pragma once
#include "iuserinfo.h"
#include "COuterUser.h"
#include <iostream>
using std::string;
class COuterUserInfo :
    public IUserInfo
{
public:
    COuterUserInfo(void);
    ~COuterUserInfo(void);
    string GetUserName();
    string GetHomeAddress();
    string GetMobileNumber();
    string GetOfficeTelNumber();
    string GetJobPosition();
    string GetHomeTelNumber();
private:
    COuterUser *m_pOuterUser;
};

OuterUserInfo.cpp

#include <stdio.h>
#include "OuterUserInfo.h"
#include "OuterUserBaseInfo.h"
#include "OuterUserHomeInfo.h"
#include "OuterUserOfficeInfo.h"
#include <iostream>
using std::cout;
using std::endl;
using std::string;
COuterUserInfo::COuterUserInfo(void)
{
   m_pOuterUser = new COuterUser();
}
COuterUserInfo::~COuterUserInfo(void)
{
   delete m_pOuterUser;
}
string COuterUserInfo::GetUserName()
{
   COuterUserBaseInfo* pBaseInfo = m_pOuterUser->GetUserBaseInfo();
   pBaseInfo->GetUserName();
   delete pBaseInfo;
   pBaseInfo = NULL;
   return "0";
}
string COuterUserInfo::GetHomeAddress()
{
   COuterUserHomeInfo* pHomeInfo = m_pOuterUser->GetUserHomeInfo();
   pHomeInfo->GetHomeAddress();
   delete pHomeInfo;
   pHomeInfo = NULL;
   return "0";
}
string COuterUserInfo::GetMobileNumber()
{
   COuterUserBaseInfo* pBaseInfo = m_pOuterUser->GetUserBaseInfo();
   pBaseInfo->GetMobileNumber();
   delete pBaseInfo;
   pBaseInfo = NULL;
   return "0";
}
string COuterUserInfo::GetOfficeTelNumber()
{
   COuterUserOfficeInfo* pOfficeInfo = m_pOuterUser->GetUserOfficeInfo();
   pOfficeInfo->GetOfficeTelNumber();
   delete pOfficeInfo;
   pOfficeInfo = NULL;
   return "0";
}
string COuterUserInfo::GetJobPosition()
{
   COuterUserOfficeInfo* pOfficeInfo = m_pOuterUser->GetUserOfficeInfo();
   pOfficeInfo->GetJobPosition();
   delete pOfficeInfo;
   pOfficeInfo = NULL;
   return "0";
}
string COuterUserInfo::GetHomeTelNumber()
{
   COuterUserHomeInfo* pHomeInfo = m_pOuterUser->GetUserHomeInfo();
   pHomeInfo->GetHomeTelNumber();
   delete pHomeInfo;
   pHomeInfo = NULL;
   return "0";
}

main.cpp

#include <stdio.h>
#include "IOuterUser.h"
#include "IUserInfo.h"
#include "UserInfo.h"
#include "OuterUserInfo.h"
void DoIt()
{
   IUserInfo* pYourGirl = new CUserInfo();
   for (int i = 0; i < 101; i += 20)
   {
      pYourGirl->GetMobileNumber();
   }
   delete pYourGirl;
}
void NowDoIt()
{
   IUserInfo* pYourGirl = new COuterUserInfo();

   for (int i = 0; i < 101; i += 20)
   {
      pYourGirl->GetMobileNumber();
   }

   delete pYourGirl;
}


int main()
{
   DoIt();

   NowDoIt();

   return 0;
}
这个人的手机号码是0000...
这个人的手机号码是0000...
这个人的手机号码是0000...
这个人的手机号码是0000...
这个人的手机号码是0000...
这个人的手机号码是0000...
这个人的手机号码是0001...
这个人的手机号码是0001...
这个人的手机号码是0001...
这个人的手机号码是0001...
这个人的手机号码是0001...
这个人的手机号码是0001...

迭代器模式

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。


main(),客户

IProject,产品接口

CProject,产品类

IIterator,迭代器接口

IProjectIterator,产品迭代器接口

CProjectIterator,产品迭代器实现类

说明:CProject实现产品类,能够返回一个迭代器的指针。这个迭代器将封装产品类里的一个数组。所以迭代器在运行Next函数时,可以遍历这个数组的所有元素。

简单来说,就是用代码实现vector::iterator或vector::const_iterator。
注意:
如果你是做Java开发,尽量不要自己写迭代器模式!省省吧,使用Java提供的Iterator一般就能满足你的要求了!

项目信息类图

IProject.h

#pragma once
#include "IProjectIterator.h"
#include <iostream>
using std::string;
class IProject
{
public:
    IProject(void)
    {
    }
    virtual ~IProject(void)
    {
    }
    virtual void Add(string name, int num, int cost) = 0;
    virtual string GetProjectInfo() = 0;
    virtual IProjectIterator* GetIterator() = 0;
    virtual void Erase() = 0;
};

Project.h

#pragma once
#include "iproject.h"
#include "IProjectIterator.h"
#include <iostream>
#include <vector>
using std::string;
using std::vector;
class CProject :
    public IProject
{
public:
    CProject(void);
    CProject(string name, int num, int cost);
    ~CProject(void);
    string GetProjectInfo();
    void Add(string name, int num, int cost);
    IProjectIterator * GetIterator();
    void Erase();
private:
    string m_name;
    int m_num;
    int m_cost;
    vector<IProject*> m_projectList;
};

Project.cpp

#include <stdio.h>
#include "Project.h"
#include "ProjectIterator.h"
#include <iostream>
#include <vector>
#include<sstream>
using std::string;
using std::vector;
using std::ostringstream;
using std::to_string;
CProject::CProject(void)
{
   m_name = "";
   m_num = 0;
   m_cost = 0;
}
CProject::CProject(string name, int num, int cost) :m_name(name), m_num(num), m_cost(cost)
{
}
CProject::~CProject(void)
{
}
string CProject::GetProjectInfo()
{
   string info = "";
   info.append("项目名称是:");
   info.append(this->m_name);
   info.append("\t项目人数:");
   info.append(to_string(m_num));
   info.append("\t项目费用:");
   info.append(to_string(m_cost));
   return info;
}
void CProject::Add(string name, int num, int cost)
{
   this->m_projectList.push_back(new CProject(name, num, cost));
}
IProjectIterator* CProject::GetIterator()
{
   return new CProjectIterator(this->m_projectList);
}
void CProject::Erase()
{
   vector<IProject*>::reverse_iterator projectDelIt = m_projectList.rbegin();
   for (; projectDelIt != m_projectList.rend(); projectDelIt++)
   {
      delete (*projectDelIt);
      (*projectDelIt) = NULL;
   }
   m_projectList.clear();
}

IIterator.h

#pragma once
class IProject;
class IIterator
{
public:
    IIterator(void)
    {
    }
    virtual ~IIterator(void)
    {
    }
    virtual bool HasNext() = 0;
    virtual IProject * Next() = 0;
};

IProjectIterator.h

#pragma once
#include "iiterator.h"
class IProject;
class IProjectIterator :
    public IIterator
{
public:
    IProjectIterator(void)
    {
    }
    virtual ~IProjectIterator(void)
    {
    }
    virtual bool HasNext() = 0;
    virtual IProject * Next() = 0;
};

ProjectIterator.h

#pragma once
#include "iprojectiterator.h"
#include "IProject.h"
#include <vector>
using std::vector;
class CProjectIterator :
    public IProjectIterator
{
public:
    CProjectIterator(vector<IProject *> pl);
    ~CProjectIterator(void);
    bool HasNext();
    IProject * Next();
private:
    vector<IProject *> m_projectList;
    size_t m_currentItem;
};

ProjectIterator.cpp

#include <stdio.h>
#include "ProjectIterator.h"
CProjectIterator::CProjectIterator(vector<IProject*> pl) : m_projectList(pl)
{
   m_currentItem = 0;
}
CProjectIterator::~CProjectIterator(void)
{
}
bool CProjectIterator::HasNext()
{
   bool b = true;
   if (m_currentItem >= m_projectList.size())
      b = false;
   return b;
}
IProject* CProjectIterator::Next()
{
   IProject* pp = m_projectList.at(m_currentItem++);
   return pp;
}

Iterator.cpp

#include <stdio.h>
#include "IProject.h"
#include "Project.h"
#include "ProjectIterator.h"
#include <iostream>
#include <vector>
#include<string>
using std::vector;
using std::cout;
using std::endl;
using std::to_string;
void DoIt()
{
   cout << "----------未使用迭代模式----------" << endl;
   vector<IProject*> projectList;

   projectList.push_back(new CProject("星球大战项目", 10, 100000));
   projectList.push_back(new CProject("扭转时空项目", 100, 10000000));
   projectList.push_back(new CProject("超人改造项目", 10000, 1000000000));

   for (int i = 4; i < 6; i++)
   {
      string name = "";
      name.append("第");
      name.append(to_string(i));
      name.append("个项目");
      projectList.push_back(new CProject(name, i * 5, i * 1000000));
   }

   vector<IProject*>::const_iterator projectIt = projectList.begin();
   for (; projectIt != projectList.end(); projectIt++)
      cout << (*projectIt)->GetProjectInfo().c_str() << endl;

   vector<IProject*>::reverse_iterator projectDelIt = projectList.rbegin();
   for (; projectDelIt != projectList.rend(); projectDelIt++)
   {
      delete (*projectDelIt);
      (*projectDelIt) = NULL;
   }
   projectList.clear();
}
void DoNew()
{
   cout << "----------使用迭代模式----------" << endl;
   IProject* pproject = new CProject();
   pproject->Add("星球大战项目", 10, 100000);
   pproject->Add("扭转时空项目", 100, 10000000);
   pproject->Add("超人改造项目", 10000, 1000000000);

   for (int i = 4; i < 6; i++)
   {
      string name = "";
      name.append("第");
      name.append(to_string(i));
      name.append("个项目");
      pproject->Add(name, i * 5, i * 1000000);
   }

   IProjectIterator* pprojectIt = pproject->GetIterator();
   while (pprojectIt->HasNext())
   {
      IProject* p = dynamic_cast<IProject*>(pprojectIt->Next());
      cout << p->GetProjectInfo().c_str() << endl;
   }
   delete pprojectIt;
   pprojectIt = NULL;
   pproject->Erase();
   delete pproject;
   pproject = NULL;
}
int main()
{
   //使用Iterator模式之前
   DoIt();

   //使用Iterator
   DoNew();

   _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
   _CrtDumpMemoryLeaks();

   return 0;
}
----------未使用迭代模式----------
项目名称是:星球大战项目        项目人数:10    项目费用:100000
项目名称是:扭转时空项目        项目人数:100   项目费用:10000000
项目名称是:超人改造项目        项目人数:10000 项目费用:1000000000
项目名称是:第4个项目   项目人数:20    项目费用:4000000
项目名称是:第5个项目   项目人数:25    项目费用:5000000
----------使用迭代模式----------
项目名称是:星球大战项目        项目人数:10    项目费用:100000
项目名称是:扭转时空项目        项目人数:100   项目费用:10000000
项目名称是:超人改造项目        项目人数:10000 项目费用:1000000000
项目名称是:第4个项目   项目人数:20    项目费用:4000000
项目名称是:第5个项目   项目人数:25    项目费用:5000000

组合模式

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

将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

优点: 1、高层模块调用简单。 2、节点自由增加。

缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。

批注:链表模式??


main(),客户

CCorpNode,抽象基类,实现基本信息

CBranchNode,树枝节点,实现Addordinate()函数和GetSubordinate()函数

CLeafNode,叶子节点,IsLeaf属性总是“true”

说明:组合模式主要是实现在CBranchNode对象里增加对其它对象的数组,如vector<CCorpNode*>,数组里可以存放CBranchNode和CLeafNode对象。这样方便进行遍历操作。

注意:组合模式有透明组合模式和安全组合模式。透明组合模式是将Addordinate和GetSubordinate这两个函数也抽象到CCorpNode基类里,这增加了操作叶子节点的难度,更易出现逻辑问题。所以尽量使用安全模式。

这个简单了,可以想像一下TreeView和TreeNode基本上是这个意思了,将很多数据组织在一块。

组织架构

Branch.h

#pragma once
#include "ibranch.h"
#include "ICorp.h"
#include <vector>
#include <iostream>
using std::vector;
using std::string;
class CBranch :
	public IBranch, ICorp
{
public:
	CBranch(void);
	CBranch(string name, string pos, int salary);
	~CBranch(void);
	void Add(ICorp *pcorp);
	vector<ICorp*> GetSubordinateInfo();
	string GetInfo();
private:
	string m_name;
	string m_position;
	int m_salary;
	vector<ICorp*> m_subordinateList;
};

BranchNode.h

#pragma once
#include "corpnode.h"
#include "CorpNode.h"
#include <vector>
#include <iostream>
using std::vector;
using std::string;
class CBranchNode :
	public CCorpNode
{
public:
	CBranchNode(void);
	CBranchNode(string name, string pos, int salary);
	~CBranchNode(void);
	void Add(CCorpNode *pcorpNode);
	vector<CCorpNode*> GetSubordinateInfo();
	bool IsLeaf();
private:
	vector<CCorpNode*> m_subordinateList;
};

CorpNode.h

#pragma once
#include <iostream>
using std::string;
class CCorpNode
{
public:
	CCorpNode();
	CCorpNode(string _name, string _pos, int _salary);
	virtual ~CCorpNode(void);
	virtual string GetInfo();
	void SetParent(CCorpNode *_pParent);
	CCorpNode * GetParent();
	virtual bool IsLeaf() = 0;
private:
	string m_name;
	string m_position;
	int m_salary;
protected:
	bool m_isLeaf;
	CCorpNode *m_pParent;
};

IBranch.h

#pragma once
#include "ICorp.h"
#include <vector>
#include <iostream>
using std::vector;
using std::string;
class IBranch
{
public:

	IBranch(void)
	{
	}

	virtual ~IBranch(void)
	{
	}
	virtual void Add(ICorp *pcorp) = 0;
	virtual vector<ICorp*> GetSubordinateInfo() = 0;
};

ICorp.h

#pragma once
#include <iostream>
using std::string;
class ICorp
{
public:

	ICorp(void)
	{
	}

	virtual ~ICorp(void)
	{
	}
	virtual string GetInfo() = 0;
};

Leaf.h

#pragma once
#include "icorp.h"
#include <iostream>
using std::string;
class CLeaf :
	public ICorp
{
public:
	CLeaf(void);
	CLeaf(string name, string pos, int salary);
	~CLeaf(void);
	string GetInfo();
private:
	string m_name;
	string m_position;
	int m_salary;
};

LeafNode.h

#pragma once
#include "corpnode.h"
class CLeafNode :
	public CCorpNode
{
public:
	CLeafNode(void);
	CLeafNode(string name, string pos, int salary);
	~CLeafNode(void);
	bool IsLeaf();
};

Branch.cpp

#include <stdio.h>
#include "Branch.h"
#include "..\CommonDeclare\Convert.h"

CBranch::CBranch(void)
{
}

CBranch::CBranch( string name, string pos, int salary ) : m_name(name), m_position(pos), m_salary(salary)
{
}

CBranch::~CBranch(void)
{
}

void CBranch::Add( ICorp *pcorp )
{
	m_subordinateList.push_back(pcorp);
}

vector<ICorp*> CBranch::GetSubordinateInfo()
{
	return this->m_subordinateList;
}

string CBranch::GetInfo()
{
	string info = "";
	info.append("姓名:");
	info.append(this->m_name);
	info.append("\t职位:");
	info.append(this->m_position);
	info.append("\t薪水:");
	info.append(CConvert::ToString(this->m_salary));
	return info;
}

BranchNode.cpp

#include <stdio.h>
#include "BranchNode.h"

CBranchNode::CBranchNode(void)
{
	m_isLeaf = false;
}

CBranchNode::CBranchNode( string name, string pos, int salary ) : CCorpNode(name, pos, salary)
{
	m_isLeaf = false;
}

CBranchNode::~CBranchNode(void)
{
}

void CBranchNode::Add( CCorpNode *pcorpNode )
{
	pcorpNode->SetParent(this);
	m_subordinateList.push_back(pcorpNode);
}

vector<CCorpNode*> CBranchNode::GetSubordinateInfo()
{
	return this->m_subordinateList;
}

bool CBranchNode::IsLeaf()
{
	return m_isLeaf;
}

CorpNode.cpp

#include <stdio.h>
#include "CorpNode.h"
#include "..\CommonDeclare\Convert.h"

CCorpNode::CCorpNode(void)
{
	m_name = "";
	m_position = "";
	m_salary = 0;
}

CCorpNode::CCorpNode(string _name, string _pos, int _salary) : m_name(_name), m_position(_pos), m_salary(_salary)
{
}

CCorpNode::~CCorpNode(void)
{
}

string CCorpNode::GetInfo()
{
	string info = "";
	info.append("姓名:");
	info.append(this->m_name);
	info.append("\t职位:");
	info.append(this->m_position);
	info.append("\t薪水:");
	info.append(CConvert::ToString(this->m_salary));
	return info;
}

void CCorpNode::SetParent( CCorpNode *_parent )
{
	this->m_pParent = _parent;
}

CCorpNode * CCorpNode::GetParent()
{
	return this->m_pParent;
}

Leaf.cpp

#include <stdio.h>
#include "Leaf.h"
#include "..\CommonDeclare\Convert.h"


CLeaf::CLeaf(void)
{
	m_name = "";
	m_position = "";
	m_salary = 0;
}

CLeaf::CLeaf( string name, string pos, int salary ) : m_name(name), m_position(pos), m_salary(salary)
{
}

CLeaf::~CLeaf(void)
{
}

string CLeaf::GetInfo()
{
	string info = "";
	info.append("姓名:");
	info.append(this->m_name);
	info.append("\t职位:");
	info.append(this->m_position);
	info.append("\t薪水:");
	info.append(CConvert::ToString(this->m_salary));
	return info;
}

LeafNode.cpp

#include <stdio.h>
#include "LeafNode.h"

CLeafNode::CLeafNode(void)
{
	m_isLeaf = true;
}

CLeafNode::CLeafNode( string name, string pos, int salary ) : CCorpNode(name, pos, salary)
{
	m_isLeaf = true;
}

CLeafNode::~CLeafNode(void)
{
}

bool CLeafNode::IsLeaf()
{
	return m_isLeaf;
}

main.cpp

// Composite.cpp : 定义控制台应用程序的入口点。
//

#include <stdio.h>
#include "BranchNode.h"
#include "LeafNode.h"
#include <vector>
#include <iostream>
using std::vector;
using std::string;
using std::cout;
using std::endl;

void DoIt()
{
	//注未使用模式调用ICorp、CLeaf、CBranch这三个类来组织。
}

string GetTreeInfo(CBranchNode * proot)
{
	vector<CCorpNode*> subordinateList = proot->GetSubordinateInfo();
	string info = "";

	vector<CCorpNode*>::const_iterator it = subordinateList.begin();
	for (; it != subordinateList.end(); it++)
	{
		if ((*it)->IsLeaf())
		{
			info.append((*it)->GetInfo());
			info.append("\n");
		}
		else
		{
			info.append((*it)->GetInfo());
			info.append("\n");
			info.append(GetTreeInfo(dynamic_cast<CBranchNode*>(*it)));
		}
	}
	return info;
}

void DoNew()
{
	CBranchNode root("赵大", "总经理", 100000);

	CBranchNode devDep("钱大", "研发部门经理", 10000);
	CBranchNode saleDep("孙大", "销售部门经理", 20000);
	CBranchNode financeDep("李大", "财务部门经理", 30000);

	CBranchNode firstDevGroup("周三也斜", "开发一组组长", 5000);
	CBranchNode secondDevGroup("吴大棒槌", "开发二组组长", 6000);

	CLeafNode a("a", "开发人员", 2000);
	CLeafNode b("b", "开发人员", 2000);
	CLeafNode c("c", "开发人员", 2000);
	CLeafNode d("d", "开发人员", 2000);
	CLeafNode e("e", "开发人员", 2000);
	CLeafNode f("f", "开发人员", 2000);
	CLeafNode g("g", "开发人员", 2000);
	CLeafNode h("h", "开发人员", 5000);
	CLeafNode i("i", "开发人员", 4000);
	CLeafNode j("j", "开发人员", 5000);
	CLeafNode k("k", "CEO秘书", 8000);
	CLeafNode zheng("郑老六", "研发部副经理", 20000);

	root.Add(&k);CEO有三个部门经理和一个秘书
	root.Add(&devDep);
	root.Add(&saleDep);
	root.Add(&financeDep);

	devDep.Add(&zheng);//开发部有一个副经理和两个小组
	devDep.Add(&firstDevGroup);
	devDep.Add(&secondDevGroup);

	firstDevGroup.Add(&a);
	firstDevGroup.Add(&b);
	firstDevGroup.Add(&c);
	secondDevGroup.Add(&d);
	secondDevGroup.Add(&e);
	secondDevGroup.Add(&f);

	saleDep.Add(&g);
	saleDep.Add(&h);

	financeDep.Add(&i);
	financeDep.Add(&j);

	cout << root.GetInfo().c_str() << endl;
	cout << GetTreeInfo(&root).c_str() << endl;
}

int main()
{
	//未使用模式的调用。
	DoIt();

	//使用组合模式后的调用。
	DoNew();
	return 0;
}
姓名:赵大      职位:总经理    薪水:100000
姓名:k 职位:CEO秘书   薪水:8000
姓名:钱大      职位:研发部门经理      薪水:10000
姓名:郑老六    职位:研发部副经理      薪水:20000
姓名:周三也斜  职位:开发一组组长      薪水:5000
姓名:a 职位:开发人员  薪水:2000
姓名:b 职位:开发人员  薪水:2000
姓名:c 职位:开发人员  薪水:2000
姓名:吴大棒槌  职位:开发二组组长      薪水:6000
姓名:d 职位:开发人员  薪水:2000
姓名:e 职位:开发人员  薪水:2000
姓名:f 职位:开发人员  薪水:2000
姓名:孙大      职位:销售部门经理      薪水:20000
姓名:g 职位:开发人员  薪水:2000
姓名:h 职位:开发人员  薪水:5000
姓名:李大      职位:财务部门经理      薪水:30000
姓名:i 职位:开发人员  薪水:4000
姓名:j 职位:开发人员  薪水:5000

观察者模式

Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

观察者模式

  • Subject被观察者
    定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。
  • Observer观察者
    观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。
  • ConcreteSubject具体的被观察者
    定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
  • ConcreteObserver具体的观察者
    每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。

传统方式用多线程技术实现监听,而线程和死循环会极大的增加开销,为了避免这种开销,可以使用观察者模式。
这种模式有多种叫法,现整理如下,每一行都是相同的东西:
主题,被观察者,调用者
订阅者,观察者,被调用者
注册,订阅

首先被观察者会维护一个可变属性A和一个分发管理对象obj(维护分发列表),
观察者需要引用被观察者的分发管理对象obj,向其注册观察可变属性A(即add进list里),因此观察者需要引入被观察者的头文件,以便使用obj;
其次,被观察者会以回调函数的形式提供一个抽象调用接口,以便调用观察者中的回调函数,变化的属性A将从以参数的形式传入回调函数,因此观察者需要引入被观察者的头文件,以便调用回调函数;
观察者在自己的类中重写回调函数,以供被观察者调用.

总结来说,观察者在自己的类中实现了注册和回调函数的实现;
被观察者提供了可变属性A,分发管理obj和回调函数接口.

被观察者,管理并调用分发列表,抽象调用接口;
观察者,注册要观察的对象和属性,重写回调函数。


主题用于管理订阅者,当发布者发生变化时,主题广播给所有订阅者,然后所有订阅者做统一动作.

主题
Subject.h

#ifndef __SUBJECT__H__
#define __SUBJECT__H__
#include "Observer.h"
#include <list>
#include <string>
using namespace std;
class Observer;
class Subject
{
public:
    Subject();
    virtual ~Subject();
    virtual void attach(Observer* obs);
    virtual void detach(Observer* obs);
    virtual void Notify();
    virtual void setState(const string& str) = 0;
    virtual string getState() = 0;

private:
    list<Observer*>* _observers;
};


class ConcreteSubject : public Subject {
public:
    ConcreteSubject();
    ~ConcreteSubject();
    void setState(const string& str);
    string getState();
private:
    string state;
};
#endif

Subject.cpp

#include "Subject.h"
#include <iostream>
#include <list>
using namespace std;

Subject::Subject() {
    _observers = new list<Observer*>;
}
Subject::~Subject() {

}

void Subject::attach(Observer* obs) {
    if (obs != NULL) {
        _observers->push_front(obs);
    }
}

void Subject::detach(Observer* obs) {
    if (obs != NULL) {
        _observers->remove(obs);
    }
}

void Subject::Notify() {

    list<Observer*>::iterator iter;//遍历更新
    for (iter = _observers->begin(); iter != _observers->end(); iter++) {
        (*iter)->update(this);
    }
}

ConcreteSubject::ConcreteSubject() {
    this->state = '\0';
}

ConcreteSubject::~ConcreteSubject() {

}

string ConcreteSubject::getState() {
    return this->state;
}

void ConcreteSubject::setState(const string& str) {
    this->state = str;
}

观察者
Observer.h

#ifndef __OBSERVER__H__
#define __OBSERVER__H__
#include "Subject.h"
#include <string>
using namespace std;
class Subject;
class Observer {
public:
    Observer();
    virtual ~Observer();
    virtual void update(Subject* subject) = 0;
    virtual void printInfo() = 0;
public:
    std::string state;

};

class ConcreteObserver:public Observer
{
public:
    ConcreteObserver(Subject* sub);
    ~ConcreteObserver();
    void update(Subject* sub);
    void printInfo();
private:
    Subject* _sub;

};
#endif

Observer.cpp

#include "Observer.h"
#include <list>
#include <iostream>

using namespace std;

Observer::Observer() {
    state = '\0';
}

Observer::~Observer() {

}

ConcreteObserver::ConcreteObserver(Subject* sub) {
    _sub = sub;
    _sub->attach(this);
}

ConcreteObserver::~ConcreteObserver() {
    _sub->detach(this);
    if (_sub != 0) {
        delete _sub;
    }
}

void ConcreteObserver::update(Subject* subject) {
    state = subject->getState();
    this->printInfo();
}

void ConcreteObserver::printInfo() {
   // string str = _sub->getState();
    cout << "ConcreteObserver observer.... " << _sub->getState() << endl;
}

main.cpp

#include "Observer.h"
#include "Subject.h"
#include <iostream>
using namespace std;
int main() {
    //新建一个被监听对象sub(主题)
    Subject* sub = new ConcreteSubject();

    //新建一个监听者obA ,并初始化为监听sub
    ConcreteObserver* obA = new ConcreteObserver(sub);
    ConcreteObserver* obB = new ConcreteObserver(sub);

    //验证此时消息为空
    obA->printInfo();
    obB->printInfo();

    //被监听者开始改变
    sub->setState("大家好,我现在已经发布了最新消息");
    //被监听者发布广播
    sub->Notify();

    return 0;
}
g++ main.cpp Subject.cpp Observer.cpp
./a.out
ConcreteObserver observer....
ConcreteObserver observer....
ConcreteObserver observer.... 大家好,我现在已经发布了最新消息
ConcreteObserver observer.... 大家好,我现在已经发布了最新消息

这是被监听者和监听者直接对接的模型,还有一种是增加了第三方通信平台,监听者向平台注册,被监听者将更新信息发送给消息平台,然后平台进行发放广播。

门面模式

Provide a unified interface to a set of interfaces in a subsystem.Facade defines a higher-level interface that makes the subsystem easier to use.

要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

门面模式注重“统一的对象”,也就是提供一个访问子系统的接口,除了这个接口不允许有任何访问子系统的行为发生。
简单说,就是将复杂的逻辑封装起来,对外公开简单的接口,由客户程序调用。

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。

这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。

意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。

缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

使用场景: 1、为复杂的模块或子系统提供外界访问的模块。 2、子系统相对独立。 3、预防低水平人员带来的风险。


main(),客户

ILetterProcess,接口

CLetterProcessImpl,信件处理的4个函数

CLetterPolice,警察

CModenPostOffice,邮局

说明:邮局对外只有一个窗口,接收信件内容和邮件地址。对内调用邮件处理的4个函数。将复杂逻辑封装在邮局的里面,当需要增加警察来检查信件时,只需在邮局内增加警察检查信件的方法。

写信过程类图

ILetterProcess.h

#pragma once
#include <iostream>
using std::string;
class ILetterProcess
{
public:
    ILetterProcess(void);
    virtual ~ILetterProcess(void);
    virtual void WriteContext(string context) = 0;
    virtual void FillEnvelope(string address) = 0;
    virtual void LetterIntoEnvelope() = 0;
    virtual void SendLetter() = 0;
};

ILetterProcess.cpp

#include <stdio.h>
#include "ILetterProcess.h"
ILetterProcess::ILetterProcess(void)
{
}
ILetterProcess::~ILetterProcess(void)
{
}

LetterprocessImpl.h

#pragma once
#include "iletterprocess.h"
class CLetterProcessImpl :
    public ILetterProcess
{
public:
    CLetterProcessImpl(void);
    ~CLetterProcessImpl(void);

    void WriteContext(string context);
    void FillEnvelope(string address);
    void LetterIntoEnvelope();
    void SendLetter();
};

LetterProcessImpl.cpp

#include <stdio.h>
#include "LetterProcessImpl.h"
#include <iostream>
using std::string;
using std::cout;
using std::endl;
CLetterProcessImpl::CLetterProcessImpl(void)
{
}
CLetterProcessImpl::~CLetterProcessImpl(void)
{
}
void CLetterProcessImpl::WriteContext(string context)
{
    cout << "填写信的内容... ..." << endl;
}
void CLetterProcessImpl::FillEnvelope(string address)
{
    cout << "填写收件人地址及姓名... ..." << endl;
}
void CLetterProcessImpl::LetterIntoEnvelope()
{
    cout << "把信放到信封中..." << endl;
}
void CLetterProcessImpl::SendLetter()
{
    cout << "邮递信件..." << endl;
}

ModenPostOffice.h

#pragma once
#include "ILetterProcess.h"
#include "LetterProcessImpl.h"
#include "LetterPolice.h"
#include <iostream>
using std::string;
class CModenPostOffice
{
public:
    CModenPostOffice(void);
    ~CModenPostOffice(void);
    void SendLetter(string context, string address);
private:
    ILetterProcess *m_pLetterProcess;
    CLetterPolice *m_pLetterPolice;
};

ModenPostOffice.cpp

#include <stdio.h>
#include "ModenPostOffice.h"
CModenPostOffice::CModenPostOffice(void)
{
    this->m_pLetterProcess = new CLetterProcessImpl();
    this->m_pLetterPolice = new CLetterPolice();
}
CModenPostOffice::~CModenPostOffice(void)
{
    delete m_pLetterProcess;
    delete m_pLetterPolice;
}
void CModenPostOffice::SendLetter( string context, string address )
{
    //帮忙写信
    m_pLetterProcess->WriteContext(context);
    //写好信封
    m_pLetterProcess->FillEnvelope(address);
    //警察要检查信件了
    m_pLetterPolice->CheckLetter(m_pLetterProcess);
    //把信放到信封中
    m_pLetterProcess->LetterIntoEnvelope();
    //邮递信件
    m_pLetterProcess->SendLetter();
}

LetterPolice.h

#pragma once
#include "ILetterProcess.h"
class CLetterPolice
{
public:
   CLetterPolice(void) {};
   ~CLetterPolice(void) {};
   void CheckLetter(ILetterProcess* pLetterProcess) {};
};

LetterPolice.cpp

#include <stdio.h>
#include "LetterPolice.h"
CLetterPolice::CLetterPolice(void)
{
}
CLetterPolice::~CLetterPolice(void)
{
}
void CLetterPolice::CheckLetter( ILetterProcess *pLetterProcess )
{

    //检查信件,此处省略一万字。
    return;
}

main.cpp

#include <stdio.h>
#include <iostream>
#include "ILetterProcess.h"
#include "LetterProcessImpl.h"
#include "ModenPostOffice.h"

using std::string;
using std::cout;
using std::endl;
void DoItByPostOffice()
{
    CModenPostOffice modenPostOffice;
    string context = "Hello, It's me, do you know who I am? I'm your old lover. I'd like to ... ...";
    string address = "Happy Road No. 666, Beijing City, China";
    modenPostOffice.SendLetter(context, address);
}
void DoItYourself()
{
    ILetterProcess *pLetterProcess = new CLetterProcessImpl();
    pLetterProcess->WriteContext("Hello, It's me, do you know who I am? I'm your old lover. I'd like to ... ...");
    pLetterProcess->FillEnvelope("Happy Road No. 666, Beijing City, China");
    pLetterProcess->LetterIntoEnvelope();
    pLetterProcess->SendLetter();
    delete pLetterProcess;
}
int main()
{
    //现在的调用方式。对于客户来说确实简单多了。
    //如需要增加逻辑,例如让警察来检查邮件。可以在邮局里完成这项工作。
    DoItByPostOffice();

    //原来的调用方式。
    DoItYourself();

    return 0;
}
填写信的内容... ...
填写收件人地址及姓名... ...
把信放到信封中...
邮递信件...
填写信的内容... ...
填写收件人地址及姓名... ...
把信放到信封中...
邮递信件...

备忘录模式

Without violating encapsulation,capture and externalize an object's internal state so that the object can be restored to this state later.

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

优点: 1、给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。 2、实现了信息的封装,使得用户不需要关心状态的保存细节。

缺点:消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。

使用场景: 1、需要保存/恢复数据的相关状态场景。 2、提供一个可回滚的操作。

访问者模式

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

BaseVisitor.h

#pragma once
#include "ivisitor.h"
#include "CommonEmployee.h"
#include "Manager.h"
#include <iostream>
using std::string;
class CBaseVisitor :
	public IVisitor
{
public:
	CBaseVisitor(void);
	~CBaseVisitor(void);
	void Visit(CCommonEmployee commonEmployee);
	void Visit(CManager manager);
	int GetTotalSalary();
private:
	string GetBasicInfo(CEmployee *pemployee);
	string GetManagerInfo(CManager manager);
	string GetCommonEmployee(CCommonEmployee employee);
	static const int MANAGER_COEFFICENT = 5;
	static const int COMMONEMPLOYEE_COEFFICENT = 2;
	int m_commonTotal;
	int m_managerTotal;
	void CalCommonSalary(int salary);
	void CalManagerSalary(int salary);
};

CommonEmployee.h

#pragma once
#include "employee.h"
#include "IVisitor.h"
#include <iostream>
using std::string;
class CCommonEmployee :
	public CEmployee
{
public:
	CCommonEmployee(void);
	~CCommonEmployee(void);
	string GetJob();
	void SetJob(string job);
	void Accept(IVisitor *pVisitor);
protected:
	string GetOtherInfo();
private:
	string m_job;
};

Employee.h

#pragma once
#include "IVisitor.h"
#include <iostream>
using std::string;
class CEmployee
{
public:
	static int MALE;
	static int FEMALE;
	CEmployee(void);
	virtual ~CEmployee(void);
	string GetName();
	void SetName(string name);
	int GetSalary();
	void SetSalary(int v);
	int GetSex();
	void SetSex(int v);
	virtual void Accept(IVisitor *pVisitor) = 0;
private:
	string m_name;
	int m_salary;
	int m_sex;
};

IVisitor.h

#pragma once

class CCommonEmployee;
class CManager;
class IVisitor
{
public:

	IVisitor(void)
	{
	}

	virtual ~IVisitor(void)
	{
	}
	virtual void Visit(CCommonEmployee commonEmployee) = 0;
	virtual void Visit(CManager manager) = 0;
	virtual int GetTotalSalary() = 0;
};

Manager.h

#pragma once
#include "employee.h"
#include "IVisitor.h"
#include <iostream>
using std::string;
class CManager :
	public CEmployee
{
public:
	CManager(void);
	~CManager(void);
	string GetPerformance();
	void SetPerformance(string per);
	void Accept(IVisitor *pVisitor);
protected:
	string GetOtherInfo();
private:
	string m_performance;
};

BaseVisitor.cpp

#include <stdio.h>
#include "..\CommonDeclare\Convert.h"
#include "BaseVisitor.h"
#include <iostream>
using std::string;
using std::cout;
using std::endl;


CBaseVisitor::CBaseVisitor(void)
{
	m_commonTotal = 0;
	m_managerTotal = 0;
}


CBaseVisitor::~CBaseVisitor(void)
{
}

void CBaseVisitor::Visit(CCommonEmployee commonEmployee)
{
	cout << this->GetCommonEmployee(commonEmployee).c_str() << endl;
	this->CalCommonSalary(commonEmployee.GetSalary());
}

void CBaseVisitor::Visit(CManager manager)
{
	cout << this->GetManagerInfo(manager).c_str() << endl;
	this->CalManagerSalary(manager.GetSalary());
}

string CBaseVisitor::GetBasicInfo(CEmployee *pemployee)
{
	string info = "";
	info.append("姓名:");
	info.append(pemployee->GetName());
	info.append("\t");
	info.append("性别:");
	info.append(CConvert::ToString(pemployee->GetSex()));
	info.append("\t");
	info.append("薪水:");
	info.append(CConvert::ToString(pemployee->GetSalary()));
	info.append("\t");
	return info;
}

string CBaseVisitor::GetManagerInfo(CManager manager)
{
	string basicInfo = this->GetBasicInfo(&manager);
	string otherInfo = "";
	otherInfo.append("业绩:");
	otherInfo.append(manager.GetPerformance());
	otherInfo.append("\t");
	basicInfo.append(otherInfo);
	return basicInfo;
}

string CBaseVisitor::GetCommonEmployee(CCommonEmployee employee)
{
	string basicInfo = this->GetBasicInfo(&employee);
	string otherInfo = "";
	otherInfo.append("工作:");
	otherInfo.append(employee.GetJob());
	otherInfo.append("\t");
	basicInfo.append(otherInfo);
	return basicInfo;
}

int CBaseVisitor::GetTotalSalary()
{
	return this->m_commonTotal + this->m_managerTotal;
}

void CBaseVisitor::CalCommonSalary(int salary)
{
	this->m_commonTotal += salary;
}

void CBaseVisitor::CalManagerSalary(int salary)
{
	this->m_managerTotal += salary;
}

CommonEmployee.cpp

#include <stdio.h>
#include "CommonEmployee.h"
#include <iostream>
using std::string;


CCommonEmployee::CCommonEmployee(void)
{
	this->m_job = "";
}


CCommonEmployee::~CCommonEmployee(void)
{
}

string CCommonEmployee::GetJob()
{
	return this->m_job;
}

void CCommonEmployee::SetJob(string job)
{
	this->m_job = job;
}

string CCommonEmployee::GetOtherInfo()
{
	string job = "";
	job.append("工作:");
	job.append(this->m_job);
	job.append("\t");
	return job;
}

void CCommonEmployee::Accept(IVisitor *pVisitor)
{
	pVisitor->Visit(*this);
}

Employee.cpp

#include <stdio.h>
#include "Employee.h"
int CEmployee::MALE = 0;
int CEmployee::FEMALE = 1;

CEmployee::CEmployee(void)
{
}


CEmployee::~CEmployee(void)
{
}

string CEmployee::GetName()
{
	return m_name;
}

void CEmployee::SetName( string name )
{
	m_name = name;
}

int CEmployee::GetSalary()
{
	return m_salary;
}

void CEmployee::SetSalary( int v )
{
	m_salary = v;
}

int CEmployee::GetSex()
{
	return m_sex;
}

void CEmployee::SetSex( int v )
{
	m_sex = v;
}

Manager.cpp

#include <stdio.h>
#include "Manager.h"
#include <iostream>
using std::string;


CManager::CManager(void)
{
	this->m_performance = "";
}


CManager::~CManager(void)
{
}

string CManager::GetPerformance()
{
	return m_performance;
}

void CManager::SetPerformance(string per)
{
	this->m_performance = per;
}

string CManager::GetOtherInfo()
{
	string info = "";
	info.append("业绩:");
	info.append(this->m_performance);
	info.append("\t");
	return info;
}

void CManager::Accept(IVisitor *pVisitor)
{
	pVisitor->Visit(*this);
}

Visitor.cpp

// Visitor.cpp : 定义控制台应用程序的入口点。

#include <stdio.h>
#include "Employee.h"
#include "CommonEmployee.h"
#include "Manager.h"
#include "BaseVisitor.h"
#include "..\CommonDeclare\Convert.h"
#include <vector>
#include <iostream>
using std::vector;
using std::cout;
using std::endl;


void MockEmployee(vector<CEmployee*> *pvce)
{
	CCommonEmployee *pZhangSan = new CCommonEmployee();
	pZhangSan->SetJob("编写Java程序,绝对的蓝领、苦工加搬运工");
	pZhangSan->SetName("张三");
	pZhangSan->SetSalary(1800);
	pZhangSan->SetSex(CEmployee::MALE);
	pvce->push_back(pZhangSan);

	CCommonEmployee *pLiSi = new CCommonEmployee();
	pLiSi->SetJob("页面美工,审美素质太不流行了!");
	pLiSi->SetName("李四");
	pLiSi->SetSalary(1900);
	pLiSi->SetSex(CEmployee::FEMALE);
	pvce->push_back(pLiSi);

	CManager *pWangWu = new CManager();
	pWangWu->SetPerformance("基本上是负值,但是我会拍马屁呀");
	pWangWu->SetName("王五");
	pWangWu->SetSalary(1900);
	pWangWu->SetSex(CEmployee::FEMALE);
	pvce->push_back(pWangWu);
}


void DoIt()
{
	vector<CEmployee*> vce;
	MockEmployee(&vce);
	vector<CEmployee*>::const_iterator readIt = vce.begin();

	CBaseVisitor visitor;
	for (; readIt != vce.end(); readIt ++)
	{
		(*readIt)->Accept(&visitor);
	}
	cout << "本公司的月工资总额是:" << CConvert::ToString(visitor.GetTotalSalary()).c_str() << endl;

	vector<CEmployee*>::reverse_iterator delIt = vce.rbegin();
	for (; delIt != vce.rend(); delIt++)
	{
		delete (*delIt);
		(*delIt) = NULL;
	}
	vce.clear();
}


int main()
{
	DoIt();
	return 0;
}
姓名:张三      性别:0 薪水:1800      工作:编写Java程序,绝对的蓝领、苦工加搬运工
姓名:李四      性别:1 薪水:1900      工作:页面美工,审美素质太不流行了!
姓名:王五      性别:1 薪水:1900      业绩:基本上是负值,但是我会拍马屁呀
本公司的月工资总额是:5600

状态模式

Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.

当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

main(),客户

CLiftState,电梯状态抽象类

CCloseingState,电梯门关闭

COpenningState,电梯门打开

CRunningState,电梯运行

CStoppingState,电梯停止

CContext,电梯的控制面板

说明:CContext保持电梯的状态,并提供操作的接口函数。当函数被调用时,CContext直接调用当前状态的相应函数。由状态的接口函数来确定是否可以执行这个动作,以及修改状态为执行这个动作后的状态。

看代码:第一块是不使用模式的做法,第二块是使用模式的做法,在main()函数里会有调用的方式。

电梯的类图

ILift.h

#pragma once
class ILift
{
public:

    ILift(void)
    {
    }

    virtual ~ILift(void)
    {
    }
    static const int OPENING_STATE = 1;
    static const int CLOSING_STATE = 2;
    static const int RUNNING_STATE = 3;
    static const int STOPPING_STATE = 4;
    virtual void SetState(int state) = 0;
    virtual void Open() = 0;
    virtual void Close() = 0;
    virtual void Run() = 0;
    virtual void Stop() = 0;
};

Lift.h

#pragma once
#include "ilift.h"
class CLift :
    public ILift
{
public:
    CLift(void);
    ~CLift(void);
    void SetState(int state);
    void Open();
    void Close();
    void Run();
    void Stop();
private:
    int m_state;
    void OpenWithoutLogic();
    void CloseWithoutLogic();
    void RunWithoutLogic();
    void StopWithoutLogic();
};

Lift.cpp

#include <stdio.h>
#include "Lift.h"
#include <iostream>
using std::cout;
using std::endl;

CLift::CLift(void)
{
    this->m_state = 0;
}

CLift::~CLift(void)
{
}

void CLift::SetState(int state)
{
    this->m_state = state;
}

void CLift::Open()
{
    switch(this->m_state)
    {
    case OPENING_STATE:
        break;
    case CLOSING_STATE:
        this->OpenWithoutLogic();
        this->SetState(OPENING_STATE);
        break;
    case RUNNING_STATE:
        break;
    case STOPPING_STATE:
        this->OpenWithoutLogic();
        this->SetState(OPENING_STATE);
        break;
    }
}

void CLift::Close()
{
    switch(this->m_state)
    {
    case OPENING_STATE:
        this->CloseWithoutLogic();
        this->SetState(CLOSING_STATE);
        break;
    case CLOSING_STATE:
        break;
    case RUNNING_STATE:
        break;
    case STOPPING_STATE:
        break;
    }
}

void CLift::Run()
{
    switch(this->m_state)
    {
    case OPENING_STATE:
        break;
    case CLOSING_STATE:
        this->RunWithoutLogic();
        this->SetState(RUNNING_STATE);
        break;
    case RUNNING_STATE:
        break;
    case STOPPING_STATE:
        this->RunWithoutLogic();
        this->SetState(RUNNING_STATE);
        break;
    }
}

void CLift::Stop()
{
    switch(this->m_state)
    {
    case OPENING_STATE:
        break;
    case CLOSING_STATE:
        this->StopWithoutLogic();
        this->SetState(CLOSING_STATE);
        break;
    case RUNNING_STATE:
        this->StopWithoutLogic();
        this->SetState(CLOSING_STATE);
        break;
    case STOPPING_STATE:
        break;
    }
}

void CLift::OpenWithoutLogic()
{
    cout << "电梯门开启..." << endl;
}

void CLift::CloseWithoutLogic()
{
    cout << "电梯门关闭..." << endl;
}

void CLift::RunWithoutLogic()
{
    cout << "电梯上下跑起来..." << endl;
}

void CLift::StopWithoutLogic()
{
    cout << "电梯停止了..." << endl;
}

LiftState.h

#pragma once
class CContext;
class CLiftState
{
public:
    CLiftState(void);
    virtual ~CLiftState(void);
    void SetContext(CContext *pContext);
    virtual void Open() = 0;
    virtual void Close() = 0;
    virtual void Run() = 0;
    virtual void Stop() = 0;
protected:
    CContext *m_pContext;
};

LiftState.cpp

#include <stdio.h>
#include "LiftState.h"

CLiftState::CLiftState(void)
{
}

CLiftState::~CLiftState(void)
{
}

void CLiftState::SetContext( CContext *pContext )
{
    m_pContext = pContext;
}

CloseingState.h

#pragma once
#include "liftstate.h"
class CCloseingState :
    public CLiftState
{
public:
    CCloseingState(void);
    ~CCloseingState(void);
    void Open();
    void Close();
    void Run();
    void Stop();
};

CloseingState.cpp

#include <stdio.h>
#include "CloseingState.h"
#include "Context.h"
#include <iostream>
using std::cout;
using std::endl;

CCloseingState::CCloseingState(void)
{
}

CCloseingState::~CCloseingState(void)
{
}

void CCloseingState::Open()
{
    this->CLiftState::m_pContext->SetLiftState(CContext::pOpenningState);
    this->CLiftState::m_pContext->GetLiftState()->Open();
}

void CCloseingState::Close()
{
    cout << "电梯门关闭..." << endl;
}

void CCloseingState::Run()
{
    this->CLiftState::m_pContext->SetLiftState(CContext::pRunningState);
    this->CLiftState::m_pContext->GetLiftState()->Run();
}

void CCloseingState::Stop()
{
    this->CLiftState::m_pContext->SetLiftState(CContext::pStoppingState);
    this->CLiftState::m_pContext->GetLiftState()->Stop();
}

OpenningState.h

#pragma once
#include "liftstate.h"
class COpenningState :
    public CLiftState
{
public:
    COpenningState(void);
    ~COpenningState(void);
    void Open();
    void Close();
    void Run();
    void Stop();
};

OpenningState.cpp

#include <stdio.h>
#include "OpenningState.h"
#include "Context.h"
#include <iostream>
using std::cout;
using std::endl;

COpenningState::COpenningState(void)
{
}

COpenningState::~COpenningState(void)
{
}

void COpenningState::Open()
{
    cout << "电梯门开启..." << endl;
}

void COpenningState::Close()
{
    this->CLiftState::m_pContext->SetLiftState(CContext::pCloseingState);
    this->CLiftState::m_pContext->GetLiftState()->Close();
}

void COpenningState::Run()
{
    //do nothing
}

void COpenningState::Stop()
{
    //do nothing
}

RunningState.h

#pragma once
#include "liftstate.h"
class CRunningState :
    public CLiftState
{
public:
    CRunningState(void);
    ~CRunningState(void);
    void Open();
    void Close();
    void Run();
    void Stop();
};

RunningState.cpp

#include <stdio.h>
#include "RunningState.h"
#include "Context.h"
#include <iostream>
using std::cout;
using std::endl;

CRunningState::CRunningState(void)
{
}

CRunningState::~CRunningState(void)
{
}

void CRunningState::Open()
{
    //do nothing
}

void CRunningState::Close()
{
    //do nothing
}

void CRunningState::Run()
{
    cout << "电梯上下跑..." << endl;
}

void CRunningState::Stop()
{
    this->CLiftState::m_pContext->SetLiftState(CContext::pStoppingState);
    this->CLiftState::m_pContext->GetLiftState()->Stop();
}

StoppingState.h

#pragma once
#include "liftstate.h"
class CStoppingState :
    public CLiftState
{
public:
    CStoppingState(void);
    ~CStoppingState(void);
    void Open();
    void Close();
    void Run();
    void Stop();
};

StoppingState.cpp

#include <stdio.h>
#include "StoppingState.h"
#include "Context.h"
#include <iostream>
using std::cout;
using std::endl;

CStoppingState::CStoppingState(void)
{
}

CStoppingState::~CStoppingState(void)
{
}

void CStoppingState::Open()
{
    this->CLiftState::m_pContext->SetLiftState(CContext::pOpenningState);
    this->CLiftState::m_pContext->GetLiftState()->Open();
}

void CStoppingState::Close()
{
    //do nothing
}

void CStoppingState::Run()
{
    this->CLiftState::m_pContext->SetLiftState(CContext::pRunningState);
    this->CLiftState::m_pContext->GetLiftState()->Run();
}

void CStoppingState::Stop()
{
    cout << "电梯停止了..." << endl;
}

Context.h

#pragma once
#include "LiftState.h"
#include "OpenningState.h"
#include "CloseingState.h"
#include "RunningState.h"
#include "StoppingState.h"
class CContext
{
public:
    CContext(void);
    ~CContext(void);
    static COpenningState *pOpenningState;
    static CCloseingState *pCloseingState;
    static CRunningState *pRunningState;
    static CStoppingState *pStoppingState;
    CLiftState * GetLiftState();
    void SetLiftState(CLiftState *pLiftState);
    void Open();
    void Close();
    void Run();
    void Stop();
private:
    CLiftState *m_pLiftState;
};

Context.cpp

#include <stdio.h>
#include "Context.h"
COpenningState* CContext::pOpenningState = NULL;
CCloseingState* CContext::pCloseingState = NULL;
CRunningState* CContext::pRunningState = NULL;
CStoppingState* CContext::pStoppingState = NULL;

CContext::CContext(void)
{
    m_pLiftState = NULL;
    pOpenningState = new COpenningState();
    pCloseingState = new CCloseingState();
    pRunningState = new CRunningState();
    pStoppingState = new CStoppingState();
}

CContext::~CContext(void)
{
    delete pOpenningState;
    pOpenningState = NULL;
    delete pCloseingState;
    pCloseingState = NULL;
    delete pRunningState;
    pRunningState = NULL;
    delete pStoppingState;
    pStoppingState = NULL;
}

CLiftState * CContext::GetLiftState()
{
    return m_pLiftState;
}

void CContext::SetLiftState(CLiftState *pLiftState)
{
    this->m_pLiftState = pLiftState;
    this->m_pLiftState->SetContext(this);
}

void CContext::Open()
{
    this->m_pLiftState->Open();
}

void CContext::Close()
{
    this->m_pLiftState->Close();
}

void CContext::Run()
{
    this->m_pLiftState->Run();
}

void CContext::Stop()
{
    this->m_pLiftState->Stop();
}

State.cpp
//定义控制台应用程序的入口点。

#include <stdio.h>
#include "ILift.h"
#include "Lift.h"
#include "Context.h"
#include "OpenningState.h"
#include "CloseingState.h"
#include "RunningState.h"
#include "StoppingState.h"
#include <iostream>
using std::cout;
using std::endl;

void DoIt()
{
    ILift.h, Lift.h, Lift.cpp
    ILift *pLift = new CLift();
    pLift->SetState(ILift::STOPPING_STATE);//电梯的初始条件是停止状态。
    pLift->Open();//首先是电梯门开启,人进去
    pLift->Close();//然后电梯门关闭
    pLift->Run();//再然后,电梯跑起来,向上或者向下
    pLift->Stop();//最后到达目的地,电梯停下来
    delete pLift;
}


void DoNew()
{
    LiftState.h, LiftState.cpp, OpenningState.h, CloseingState.h, RunningState.h, StoppingState.h
    Context.h, Context.cpp
    CContext context;
    CCloseingState closeingState;
    context.SetLiftState(&closeingState);
    context.Close();
    context.Open();
    context.Run();
    context.Stop();
}

int main()
{
    cout << "----------使用模式之前----------" << endl;
    DoIt();
    cout << "----------使用模式之后----------" << endl;
    DoNew();

    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
    _CrtDumpMemoryLeaks();
    return 0;
}
----------使用模式之前----------
电梯门开启...
电梯门关闭...
电梯上下跑起来...
电梯停止了...
----------使用模式之后----------
电梯门关闭...
电梯门开启...

解释器模式

Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

享元模式

Use sharing to support large numbers of fine-grained objects efficiently.

使用共享对象可有效地支持大量的细粒度的对象。

桥梁模式

Decouple an abstraction from its implementation so that the two can vary independently.

将抽象和实现解耦,使得两者可以独立地变化。


main(),客户

IProduct,产品接口

CHouse,房子

CIPod,ipod

CClothes,服装

CNewCorp,桥梁类,MakeMoney()是桥梁方法

CNewHouseCorp,只能生产房子,所以构造函数是CHouse*

CShanZhaiCorp,什么赚钱就生产什么,所以构造函数是IProduct*

说明:客户直接使用CNewHouseCorp和CShanZhaiCorp类,在main()函数里构造产品,然后传到这两个类里。这两个类的MakeMoney()函数,先调用基类的MakeMoney(),然后分别执行各自的逻辑。

注意:CNewCorp起到了桥梁的作用。可以分别增加产品和公司。

使用快速变化的类图

NewCorp.h

#pragma once
#include "IProduct.h"
class CNewCorp
{
public:
    CNewCorp(IProduct *pproduct);
    virtual ~CNewCorp(void);
    void MakeMoney();
private:
    IProduct *m_pProduct;
};

NewCorp.cpp

#include <stdio.h>
#include "NewCorp.h"
CNewCorp::CNewCorp( IProduct *pproduct )
{
    this->m_pProduct = pproduct;
}
CNewCorp::~CNewCorp(void)
{
}
void CNewCorp::MakeMoney()
{
    //每个公司都是一样,先生产
    this->m_pProduct->BeProducted();

    //然后销售
    this->m_pProduct->BeSelled();
}

NewHouseCorp.h

#pragma once
#include "newcorp.h"
#include "House.h"
class CNewHouseCorp :
    public CNewCorp
{
public:
    CNewHouseCorp(CHouse *pHouse);
    ~CNewHouseCorp(void);
    void MakeMoney();
};

NewHouseCorp.cpp

#include <stdio.h>
#include "NewHouseCorp.h"
#include <iostream>
using std::cout;
using std::endl;
CNewHouseCorp::CNewHouseCorp(CHouse *pHouse) : CNewCorp(pHouse)
{
}
CNewHouseCorp::~CNewHouseCorp(void)
{
}
void CNewHouseCorp::MakeMoney()
{
    this->CNewCorp::MakeMoney();
    cout << "房地产公司赚大钱了..." << endl;
}

ShanZhaiCorp.h

#pragma once
#include "newcorp.h"
#include "IProduct.h"
class CShanZhaiCorp :
    public CNewCorp
{
public:
    CShanZhaiCorp(IProduct *pproduct);
    ~CShanZhaiCorp(void);
    void MakeMoney();
};

ShanZhaiCorp.cpp

#include <stdio.h>
#include "ShanZhaiCorp.h"
#include <iostream>
using std::cout;
using std::endl;
CShanZhaiCorp::CShanZhaiCorp(IProduct *pproduct) : CNewCorp(pproduct)
{
}
CShanZhaiCorp::~CShanZhaiCorp(void)
{
}
void CShanZhaiCorp::MakeMoney()
{
    this->CNewCorp::MakeMoney();
    cout << "我赚钱呀..." << endl;
}

IProduct.h

#pragma once
class IProduct
{
public:
    IProduct(void)
    {
    }
    virtual ~IProduct(void)
    {
    }
    virtual void BeProducted() = 0;
    virtual void BeSelled() = 0;
};

House.h

#pragma once
#include "iproduct.h"
class CHouse :
    public IProduct
{
public:
    CHouse(void);
    ~CHouse(void);
    void BeProducted();
    void BeSelled();
};

House.cpp

#include <stdio.h>
#include "House.h"
#include <iostream>
using std::cout;
using std::endl;
CHouse::CHouse(void)
{
}
CHouse::~CHouse(void)
{
}
void CHouse::BeProducted()
{
    cout << "生产出的房子是这个样子的..." << endl;
}
void CHouse::BeSelled()
{
    cout << "生产出的房子卖出去了..." << endl;
}

Clothes.h

#pragma once
#include "iproduct.h"
class CClothes :
    public IProduct
{
public:
    CClothes(void);
    ~CClothes(void);
    void BeProducted();
    void BeSelled();
};

Clothes.cpp

#include <stdio.h>
#include "Clothes.h"
#include <iostream>
using std::cout;
using std::endl;
CClothes::CClothes(void)
{
}
CClothes::~CClothes(void)
{
}
void CClothes::BeProducted()
{
    cout << "生产出的衣服是这个样子的..." << endl;
}
void CClothes::BeSelled()
{
    cout << "生产出的衣服卖出去了..." << endl;
}

IPod.h

#pragma once
#include "iproduct.h"
class CIPod :
    public IProduct
{
public:
    CIPod(void);
    ~CIPod(void);
    void BeProducted();
    void BeSelled();
};

IPod.cpp

#include <stdio.h>
#include "IPod.h"
#include <iostream>
using std::cout;
using std::endl;
CIPod::CIPod(void)
{
}
CIPod::~CIPod(void)
{
}
void CIPod::BeProducted()
{
    cout << "生产出的ipod是这个样子的..." << endl;
}
void CIPod::BeSelled()
{
    cout << "生产出的ipod卖出去了..." << endl;
}

Bridge.cpp
//定义控制台应用程序的入口点。

#include <stdio.h>
#include "NewHouseCorp.h"
#include "Clothes.h"
#include "IPod.h"
#include "ShanZhaiCorp.h"
#include <iostream>
using std::cout;
using std::endl;

void DoNewRun1()
{
    cout << "----------房地产公司是这样运行的----------" << endl;
    CHouse house;
    CNewHouseCorp newHouseCorp(&house);
    newHouseCorp.MakeMoney();
    cout << endl;

    cout << "----------山寨公司是这样运行的----------" << endl;
    CClothes clothes;
    CShanZhaiCorp shanZhaiCorp(&clothes);
    shanZhaiCorp.MakeMoney();
    cout << endl;
}

void DoNewRun2()
{
    cout << "----------房地产公司是这样运行的----------" << endl;
    CHouse house;
    CNewHouseCorp newHouseCorp(&house);
    newHouseCorp.MakeMoney();
    cout << endl;

    cout << "----------山寨公司是这样运行的----------" << endl;
    CIPod ipod;
    CShanZhaiCorp shanZhaiCorp(&ipod);
    shanZhaiCorp.MakeMoney();
    cout << endl;
}

int main()
{
    //只有两家公司,一家是房地产公司,另一家公司是衣服赚钱就生产衣服
    DoNewRun1();

    //只有两家公司,一家是房地产公司,另一家公司是ipod赚钱就生产ipod
    DoNewRun2();

    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
    _CrtDumpMemoryLeaks();
    return 0;
}
----------房地产公司是这样运行的----------
生产出的房子是这个样子的...
生产出的房子卖出去了...
房地产公司赚大钱了...
----------山寨公司是这样运行的----------
生产出的衣服是这个样子的...
生产出的衣服卖出去了...
我赚钱呀...
----------房地产公司是这样运行的----------
生产出的房子是这个样子的...
生产出的房子卖出去了...
房地产公司赚大钱了...
----------山寨公司是这样运行的----------
生产出的ipod是这个样子的...
生产出的ipod卖出去了...
我赚钱呀...

J2EE 模式

这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。

MVC 模式

MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。

  • Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
  • View(视图) - 视图代表模型包含的数据的可视化。
  • Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。

我们将创建一个作为模型的 Student 对象。StudentView 是一个把学生详细信息输出到控制台的视图类,StudentController 是负责存储数据到 Student 对象中的控制器类,并相应地更新视图 StudentView。

MVCPatternDemo,我们的演示类使用 StudentController 来演示 MVC 模式的用法。

Student.java


public class Student {
   private String rollNo;
   private String name;
   public String getRollNo() {
      return rollNo;
   }
   public void setRollNo(String rollNo) {
      this.rollNo = rollNo;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}

StudentView.java

public class StudentView {
   public void printStudentDetails(String studentName, String studentRollNo){
      System.out.println("Student: ");
      System.out.println("Name: " + studentName);
      System.out.println("Roll No: " + studentRollNo);
   }
}

StudentController.java


public class StudentController {
   private Student model;
   private StudentView view;

   public StudentController(Student model, StudentView view){
      this.model = model;
      this.view = view;
   }

   public void setStudentName(String name){
      model.setName(name);
   }

   public String getStudentName(){
      return model.getName();
   }

   public void setStudentRollNo(String rollNo){
      model.setRollNo(rollNo);
   }

   public String getStudentRollNo(){
      return model.getRollNo();
   }

   public void updateView(){
      view.printStudentDetails(model.getName(), model.getRollNo());
   }
}

MVCPatternDemo.java


public class MVCPatternDemo {
   public static void main(String[] args) {

      //从数据库获取学生记录
      Student model  = retrieveStudentFromDatabase();

      //创建一个视图:把学生详细信息输出到控制台
      StudentView view = new StudentView();

      StudentController controller = new StudentController(model, view);

      controller.updateView();

      //更新模型数据
      controller.setStudentName("John");

      controller.updateView();
   }

   private static Student retrieveStudentFromDatabase(){
      Student student = new Student();
      student.setName("Robert");
      student.setRollNo("10");
      return student;
   }
}
Student:
Name: Robert
Roll No: 10
Student:
Name: John
Roll No: 10

业务代表模式

业务代表模式(Business Delegate Pattern)用于对表示层和业务层解耦。它基本上是用来减少通信或对表示层代码中的业务层代码的远程查询功能。在业务层中我们有以下实体。

  • 客户端(Client) - 表示层代码可以是 JSP、servlet 或 UI java 代码。
  • 业务代表(Business Delegate) - 一个为客户端实体提供的入口类,它提供了对业务服务方法的访问。
  • 查询服务(LookUp Service) - 查找服务对象负责获取相关的业务实现,并提供业务对象对业务代表对象的访问。
  • 业务服务(Business Service) - 业务服务接口。实现了该业务服务的实体类,提供了实际的业务实现逻辑。

我们将创建 Client、BusinessDelegate、BusinessService、LookUpService、JMSService 和 EJBService 来表示业务代表模式中的各种实体。

BusinessDelegatePatternDemo,我们的演示类使用 BusinessDelegate 和 Client 来演示业务代表模式的用法。

BusinessService.java

public interface BusinessService {
   public void doProcessing();
}

EJBService.java

public class EJBService implements BusinessService {

   @Override
   public void doProcessing() {
      System.out.println("Processing task by invoking EJB Service");
   }
}

JMSService.java

public class JMSService implements BusinessService {

   @Override
   public void doProcessing() {
      System.out.println("Processing task by invoking JMS Service");
   }
}

BusinessLookUp.java

public class BusinessLookUp {
   public BusinessService getBusinessService(String serviceType){
      if(serviceType.equalsIgnoreCase("EJB")){
         return new EJBService();
      }else {
         return new JMSService();
      }
   }
}

BusinessDelegate.java

public class BusinessDelegate {
   private BusinessLookUp lookupService = new BusinessLookUp();
   private BusinessService businessService;
   private String serviceType;

   public void setServiceType(String serviceType){
      this.serviceType = serviceType;
   }

   public void doTask(){
      businessService = lookupService.getBusinessService(serviceType);
      businessService.doProcessing();
   }
}

Client.java

public class Client {

   BusinessDelegate businessService;

   public Client(BusinessDelegate businessService){
      this.businessService  = businessService;
   }

   public void doTask(){
      businessService.doTask();
   }
}

BusinessDelegatePatternDemo.java

public class BusinessDelegatePatternDemo {

   public static void main(String[] args) {

      BusinessDelegate businessDelegate = new BusinessDelegate();
      businessDelegate.setServiceType("EJB");

      Client client = new Client(businessDelegate);
      client.doTask();

      businessDelegate.setServiceType("JMS");
      client.doTask();
   }
}
Processing task by invoking EJB Service
Processing task by invoking JMS Service

组合实体模式

数据访问对象模式

前端控制器模式

拦截过滤器模式

服务定位器模式

传输对象模式

传输对象模式(Transfer Object Pattern)用于从客户端向服务器一次性传递带有多个属性的数据。传输对象也被称为数值对象。传输对象是一个具有 getter/setter 方法的简单的 POJO 类,它是可序列化的,所以它可以通过网络传输。它没有任何的行为。服务器端的业务类通常从数据库读取数据,然后填充 POJO,并把它发送到客户端或按值传递它。对于客户端,传输对象是只读的。客户端可以创建自己的传输对象,并把它传递给服务器,以便一次性更新数据库中的数值。以下是这种设计模式的实体。

  • 业务对象(Business Object) - 为传输对象填充数据的业务服务。
  • 传输对象(Transfer Object) - 简单的 POJO,只有设置/获取属性的方法。
  • 客户端(Client) - 客户端可以发送请求或者发送传输对象到业务对象。

我们将创建一个作为业务对象的 StudentBO 和作为传输对象的 StudentVO,它们都代表了我们的实体。

TransferObjectPatternDemo,我们的演示类在这里是作为一个客户端,将使用 StudentBO 和 Student 来演示传输对象设计模式。

StudentVO.java

public class StudentVO {
   private String name;
   private int rollNo;

   StudentVO(String name, int rollNo){
      this.name = name;
      this.rollNo = rollNo;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public int getRollNo() {
      return rollNo;
   }

   public void setRollNo(int rollNo) {
      this.rollNo = rollNo;
   }
}

StudentBO.java

import java.util.ArrayList;
import java.util.List;

public class StudentBO {

   //列表是当作一个数据库
   List<StudentVO> students;

   public StudentBO(){
      students = new ArrayList<StudentVO>();
      StudentVO student1 = new StudentVO("Robert",0);
      StudentVO student2 = new StudentVO("John",1);
      students.add(student1);
      students.add(student2);
   }
   public void deleteStudent(StudentVO student) {
      students.remove(student.getRollNo());
      System.out.println("Student: Roll No "
      + student.getRollNo() +", deleted from database");
   }

   //从数据库中检索学生名单
   public List<StudentVO> getAllStudents() {
      return students;
   }

   public StudentVO getStudent(int rollNo) {
      return students.get(rollNo);
   }

   public void updateStudent(StudentVO student) {
      students.get(student.getRollNo()).setName(student.getName());
      System.out.println("Student: Roll No "
      + student.getRollNo() +", updated in the database");
   }
}

TransferObjectPatternDemo.java

public class TransferObjectPatternDemo {
   public static void main(String[] args) {
      StudentBO studentBusinessObject = new StudentBO();

      //输出所有的学生
      for (StudentVO student : studentBusinessObject.getAllStudents()) {
         System.out.println("Student: [RollNo : "
         +student.getRollNo()+", Name : "+student.getName()+" ]");
      }

      //更新学生
      StudentVO student =studentBusinessObject.getAllStudents().get(0);
      student.setName("Michael");
      studentBusinessObject.updateStudent(student);

      //获取学生
      studentBusinessObject.getStudent(0);
      System.out.println("Student: [RollNo : "
      +student.getRollNo()+", Name : "+student.getName()+" ]");
   }
}
Student: [RollNo : 0, Name : Robert ]
Student: [RollNo : 1, Name : John ]
Student: Roll No 0, updated in the database
Student: [RollNo : 0, Name : Michael ]

消息总线

什么是消息总线?

对象的关系之间一般有:依赖、关联、聚合、组合和继承,他们的耦合程度也是依次加强!大规模开发过程中,对象很多,关联关系很复杂,没有统一、简介的方法去管理对象的关系将会导致对象关系和蜘蛛网一样,或者循环依赖问题。
基于消息总线技术可以有效解决这些问题,对象通过消息联系而不是直接依赖或者关联。

消息总线的关键技术

  • 通用的消息类型
  • 消息注册
  • 消息分发

通用的消息定义

我们需要一种泛型的函数签名来定义成一个通用的消息格式。同时需要我们可以还需要定义一个主题类型,让订阅该主题的接受者接收此消息。
我们可以使用:std::function<Ret(Args...)>作为通用的函数签名。

消息的注册

总线内部维护了一个消息列表,当需要发送消息时,会遍历消息列表,从中查找是否有合适的消息和消息接收者,找到合适的接受者之后再次广播。
消息由:消息主题+泛型函数组成。topic + std::function<Ret(Args...)>这个泛型函数可能是所有的可调用对象,例如:普通函数、成员函数、函数对象、std::function和lambda表达式。消息的统一格式为std::function<Ret(Args...)>所以首先应该讲各种调用类型转换成该类型,格式统一后就可以将消息保存起来,以便后续分发(保存消息的方法见后面章节)。
接下来我们实现一个函数类型萃取的对下。

普通函数转换为std::function

//前置声明
template<typename T>
struct function_traits;

//普通函数
template<typename Ret, typename...Args>
struct function_traits<Ret(Args...)>
{
public:
	enum {arity = sizeof...(Args)};			//获取参数数量
	typedef Ret function_type(Args...);		//定义函数类型
	typedef Ret return_type;
	using stl_function_type = std::function<function_type>;	//stl function类型  lambda可转换成stl function
	typedef Ret(*pointer)(Args...);

	template<size_t I>
	struct args
	{
		static_assert(I < arity, "index is out of range");
		//类似bind(_Binder) 源码实现,保存参数并且随时可用.
		using type = typename std::tuple_element<I, std::tuple<Args...>>::type;
	};
};

函数指针转换为std::function

函数指针,通常在C语言中经常使用,他的声明方式通常如下:

typedef void(*PFUNC)(int);

所以为了我们的函数类型萃取支持函数指针,我们需要将其返回值和入参提取出来。
具体实现如下:

//函数指针
template<typename Ret, typename...Args>
struct function_traits<Ret(*)(Args...)>
	: public function_traits<Ret(Args...)> {};

提取std::function类

这个就比较容易了,入参和返回值直接提取即可。

//std functional
template<typename Ret, typename...Args>
struct function_traits<std::function<Ret(Args...)>>
	: public function_traits<Ret(Args...)> {};

成员函数转换为std::function

这里需要特别注意的是,成员函数的调用一定是要有具体对象调用的。除非这个函数是静态函数(这个和普通函数类似)。所以我们需要函数类型和具体的调用对象。

//直接根据参数调用
template<typename ReturnType, typename ClassType, typename...Args>
void  help1(ReturnType(ClassType::*f)(Args...), ClassType& obj, Args&&...args)
{
	std::function<ReturnType(Args...)> func = [&obj, f, &args...](Args...) {
		return (obj.*f)(std::forward<Args>(args)...);
	};
	func(std::forward<Args>(args)...);
}

//返回可调用实体  此时Args可由具体调用时传入
template<typename ReturnType, typename ClassType, typename...Args>
std::function<ReturnType(Args...)>  help2(ReturnType(ClassType::*f)(Args...), ClassType& obj)
{
	std::function<ReturnType(Args...)> func = [&obj, f](Args&&...args) {
		return (obj.*f)(std::forward<Args>(args)...);
	};
	//func(std::forward<Args>(args)...);
	return func;
}

成员函数转换为std::function的更多细节

刚刚我们事先的成员函数虽然支持不同入参和返回类型,但是函数类型例如const类型的函数,并没有支持。接下里需要实现包含不同限定类型的函数。我们可使用宏定义的方式(此方法在标准库、STL库中多次被使用)实现。

//member functional
#define FUNCTION_TRAITS(...) \
template<typename ReturnType, typename ClassType, typename...Args> \
struct function_traits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : \
function_traits<ReturnType(Args...)>{}; \

FUNCTION_TRAITS();
FUNCTION_TRAITS(const);
FUNCTION_TRAITS(volatile);
FUNCTION_TRAITS(const volatile);

可以看到将const等类型扩展到函数限定符位置。

可调用对象转换为std::function

struct CallObject
{
	void operator()()
	{
		cout << "CallObject" << endl;
	}
};

//函数对象 模板实现时需要具体对象类型
template<typename Callable>
struct function_traits : function_traits<decltype(&Callable::operator())> {};

void testFunctionObject()
{
	auto f = to_function(CallObject());	//转换为std::function
	f();
}

将各类可调用对象转换为std::function函数实现

//转换成stl的function
template<typename Function>
typename function_traits<Function>::stl_function_type to_function(const Function& lambda)
{
	return static_cast<function_traits<Function>::stl_function_type>(lambda);
}
template<typename Function>
typename function_traits<Function>::stl_function_type to_function(Function&& lambda)
{
	return static_cast<function_traits<Function>::stl_function_type>(std::forward<Function>(lambda));
}

//转换成仿函数指针
template<typename Function>
typename function_traits<Function>::pointer to_function_pointer(const Function& lambda)
{
	return static_cast<function_traits<Function>::pointer>(lambda);
}

通过以上方式我们可以实现一个接受泛型类型的消息,接下里我们需要将各类消息保存起来,以便分发调用。
下面介绍消息保存和分发。

消息保存:由于消息类型有不同的返回值以及入参,这里可以使用之前介绍的Any作为消息载体
消息分发:这个就比较容易了,取出合适的函数对象(消息)直接调用即可

消息总线设计思想

消息总线融和了观察者和中介者模式,通过类型擦除擦除具体消息类型(Any)。观察者模式用来维护主题和适当的时候向观察者广播消息。中介者模式主要用来降低观察者模式互相依赖产生的耦合性。
消息总线维护的消息体是所有类型的可调用对象,没有对象之间的直接调用,更没有接口继承,主题和观察者仅仅是通过某种类型的消息联系起来,这个消息就是简单的返回值类型和入参。

下图是消息总线时序图,很好的说明的消息总线工作原理(来自原书)
消息总线时序图

其中主要的几个点就是:
1.观察者注册消息体
2.消息总线保存消息体
3.主题对象发送消息
4.消息总线调用合适主题的消息体
5.观察者收到消息并处理

完整的消息总线

class MessageBus
{
public:
	//注册消息
	template<typename F>
	void attach(F&& f, const string& topic = "")
	{
		auto func = to_function(std::forward<F>(f));
		add(topic, std::move(func));
	}

	//发送消息 没有参数
	template<typename R>
	void send(const string& topic = "")
	{
		using function_type = std::function<R()>;
		string strMsg = topic + typeid(function_type).name();
		auto range = m_map.equal_range(strMsg);
		for (auto iter = range.first; iter != range.second; ++iter)
		{
			auto f = iter->second.cast<function_type>();
			f();
		}
	}
	//发送消息 有参数
	template<typename R, typename... Args>
	void send(Args&&...args, const string& topic = "")
	{
		using function_type = std::function<R(Args...)>;
		string strMsg = topic + typeid(function_type).name();
		auto range = m_map.equal_range(strMsg);
		for (auto iter = range.first; iter != range.second; ++iter)
		{
			auto f = iter->second.cast<function_type>();
			f(std::forward<Args>(args)...);
		}
	}
	//移除某个主题 需要主题和消息类型
	template<typename R, typename... Args>
	void remove(const string& topic = "")
	{
		using function_type = std::function<R(Args...)>;
		string strMsg = topic + typeid(function_type).name();
		auto range = m_map.equal_range(strMsg);
		m_map.erase(range.first, range.second);
	}

private:
	template<typename F>
	void add(const string& topic, F&& f)
	{
		string strMsg = topic + typeid(F).name();
		m_map.emplace(std::move(strMsg), std::forward<F>(f));
	}

private:
	std::multimap<string, Any> m_map;
};

测试代码如下:

MessageBus g_bus;
string g_topic = "drive";	//主题类型
struct Subject
{
    //主题对象发送某种消息,
	void send(const string& topic)
	{
		g_bus.send<void, int>(50, topic);
	}
};

struct Car
{
	Car()
	{
		//注册到消息总线
		g_bus.attach([this](int speed) {drive(speed); }, g_topic);
	}
	void drive(int speed)
	{
	    //观察者对象接收到某种消息的响应体(lambda封装)
		cout << "car drive:" << speed << endl;
	}
};

struct Bus
{
	Bus()
	{
		//注册到消息总线
		g_bus.attach([this](int speed) {drive(speed); }, g_topic);
	}
	void drive(int speed)
	{
	    //观察者对象接收到某种消息的响应体(lambda封装)
		cout << "bus drive:" << speed << endl;
	}
};

void testBus()
{
	Subject subject;
	Car car;
	Bus bus;
	subject.send(g_topic);
	cout << "---------------" << endl;
	subject.send("");
}

不出所料,观察者Car和Bus接收到主题"drive"消息,由消息体触发drive函数调用。

复杂的对象关系梳理
我们上面实现的仅仅是简单的发送主题,然后响应。如果我们希望,观察者受到消息后,可以进行“回复”,这时候消息总线的优势就更一步体现了,我们只需重新注册一种主题即可。

MessageBus g_bus;
string g_topic = "drive";	//主题类型
string g_callbacktopic = "driveok";
struct Subject
{
	Subject()
	{
		g_bus.attach([this]{driveok(); }, g_callbacktopic);
	}

	void send(const string& topic)
	{
		g_bus.send<void, int>(50, topic);
	}

	void driveok()
	{
		cout << "driveok" << endl;
	}
};

struct Car
{
	Car()
	{
		//注册到消息总线
		g_bus.attach([this](int speed) {drive(speed); }, g_topic);
	}
	void drive(int speed)
	{
		cout << "car drive:" << speed << endl;
		//额外增加处理函数
		g_bus.send<void>(g_callbacktopic);
	}
};

struct Bus
{
	Bus()
	{
		//注册到消息总线
		g_bus.attach([this](int speed) {drive(speed); }, g_topic);
	}
	void drive(int speed)
	{
		cout << "bus drive:" << speed << endl;
	}
};

void testBus()
{
	Subject subject;
	Car car;
	Bus bus;
	subject.send(g_topic);
	cout << "---------------" << endl;
	subject.send("");
}

可以看到,Car注册了回复主题,在执行完成后,通知消息总线即可实现“回复”功能。

思考:
其实我们可将消息总线和状态机结合一下,当处于某种状态执行某些操作,然后此操作完成后可以选择继续执行某些操作,这些操作可以是不同的主题类型。
消息总线将复杂对象关系简化了,降低了对象关系的复杂度和耦合度,但是也要注意消息总线的使用场景,对象关系很简单的时候使用,反而将系统变的很复杂,在对象关系多且复杂的场景,消息总线才能更好的发挥作用。

个人总结:
消息总线的思想是总线接管所有消息处理逻辑,因此总线需要将所有函数格式化为统一接口,格式化时需要传入被调用函数的地址,被调用函数的参数类型,被调用函数的参数(数据).

注意:
消息总线案例不完美,需要增加多个发布者,同时解耦总线和发布者,而不是搞成一个。

回调模式

回调函数的简单代码实现如下:

public class ConcretSubject {
   private Callback callback;

   public void register(Callback callback) {
       this.callback = callback;
   }

   public void call() {
       callback.onCall();
   }
}
public interface Callback {
   void onCall();
}
public class Main {

   public static void main(String[] args) {
       ConcretSubject subject = new ConcretSubject();
       Callback callback = new Callback() {
           @Override
           public void onCall() {
               System.out.println("call");
           }
       };
       subject.register(callback);
       subject.call();
   }
}

通过对比,我们发现,观察者模式和回调函数模式及其相似,差别仅在于在观察者模式中,被观察者维护这一个观察者列表,而在回调模式中,“被观察者”只是保存了一个“观察者”。这就是形式上的终极区别。

也就是说,回调函数是一种特殊的观察者模式,是一种一对一的观察者模式。

参考链接:
https://www.cnblogs.com/cbf4life/
https://www.cnblogs.com/wanggary/archive/2011/04/07/2008796.html
https://www.cnblogs.com/cbf4life/
https://www.cnblogs.com/wanggary/archive/2011/04/07/2008796.html
https://blog.csdn.net/xufeng0991/article/details/50267675

posted @ 2020-05-11 06:20  多弗朗强哥  阅读(282)  评论(0编辑  收藏  举报