前言

[本文档长期更新中……]

设计模式曾经是国内开发界中一个很火热的概念
提及软件必谈架构;提及开发必谈模式
在所谓的潮流之后,是计算机行业对于新鲜事物的过渡吹捧
但是这些东西真的是新鲜的吗?
今天我们简要的谈一谈什么是设计模式,它又可以使用在什么地方

所谓的设计模式,其实可以理解为开发层面的软件书写套路
他可以通过传授和总结一些书写技巧,帮助我们在写项目的时候呈现更好的代码复用性和扩展性
至于可读性?
鉴于九成的程序员都不写、不更新注释,这个不在讨论范围之内-v-

鉴于以上内容,设计模式仅仅需要掌握常见的部分即可,不用死记细节,毕竟咱随时可以定义一个新模式

基础概念

设计模式的几大特性:
关于设计性的原则:

开放-封闭原则:你应该拥抱变化,但是仍坚守自己【留下对未来业务的兼容性,并不允许修改已有的功能】
里氏替换原则:一代应该比一代强【子类应该可以替代父类干活】

关于低耦合的原则:

合成/聚合复用原则:合伙比赠与更高效【少用继承,多用聚合】
迪米特法则:保持社交距离【不用直接通信的类不应当有任何的直接接触】
单一职责原则:少管闲事【一个类只应当负责一种功能】

四大类型

1.创建型模式

创建型模式,很简单,就是将创建一个对象的代码给封装起来,反复、花式调用

1.1工厂模式(简单、抽象)

我们先看一下总的工厂模式的思想,

工厂方法.png

简单工厂:
简单工厂,其实就是将一个创建单一的一类对象A的过程打包,
由于这个对象会被频繁创建,所以利用一个类(简单工厂类)实现一个函数,在函数里面创建
然后我们创建一个简单工厂类,就可以调用这个函数创建这个对象A了。
当然,多个函数就可以创建多个不同对象。

以下是他的uml:

简单工厂.png

同样,我们给出一份简单的示例代码:

#include <iostream>
#include <string>
#include <memory>
using namespace std;
class product
{
public:
    product() {};
    int val;
    virtual int GetVal() = 0;
    virtual void CoutVal() = 0;
};

class productA :public product
{
public:
    productA(int inum){
        val = inum;
    };
    int GetVal() override{
        return val;
    }
    void CoutVal() override{
        cout << "productA val:" << GetVal() << endl;
    }
};

class productB :public product
{
public:
    productB(int inum){
        val = inum;
    };
    int GetVal() override{
        return val;
    }
    void CoutVal() override {
        cout << "productB val:" << GetVal() << endl;
    }
};

class productC :public product
{
public:
    productC(int inum){
        val = inum;
    };
    int GetVal() override{
        return val;
    }
    void CoutVal() override {
        cout << "productC val:" << GetVal() << endl;
    }
};

template  <class T>
class simple_factory
{
public:
    std::shared_ptr<T> CreatePrd(string istr)
    {
        int param = 0;
        if (istr == "A") {
            param = 1;
            return std::make_shared<productA>(productA(param));
        }
        else if (istr == "B") {
            param = 2;
            return std::make_shared<productB>(productB(param));
        }
        else if (istr == "C"){
            param = 3;
            return std::make_shared<productC>(productC(param));
        }
        else {
            return nullptr;
        }
    }

    product* CreatePrd1(string istr)
    {
        if (istr == "A"){
            return new productA(1);
        }
        else if (istr == "B"){
            return new productB(2);
        }
        else if (istr == "C") {
            return new productC(3);
        }
        else {
            return nullptr;
        }
    }
};

int main()
{
    simple_factory<product> FAC;
    auto pa=FAC.CreatePrd("A");
    auto pb = FAC.CreatePrd("B");
    auto pc = FAC.CreatePrd("C");

    if (pa && pb && pc) {
          pa->CoutVal();
          pb->CoutVal();
          pc->CoutVal();
    }
    getchar();
}

抽象工厂:
抽象工厂不再满足于创建一个固定的一类对象A,而是想要见招拆招的创建对象like A,对象like B
所以我们也需要为这对象提供不同的工厂类,那为什么不在一个工厂里面用不同的流水线(函数)完成这一创建过程呢
我们需要控制一个工厂的大小,如果某一个工厂太过臃肿,那就是真的大而不能倒了……

以下是他的uml:
抽象工厂.png

我们还是照例使用一段示例代码来体会一下:

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

class product
{
public:
    product() {};
    int val;
    virtual int GetVal() = 0;
    virtual void CoutVal() = 0;
};

class productA :public product
{
public:
    productA(int inum)
    {
        val = inum;
    };
    int GetVal() override
    {
        return val;
    }
    void CoutVal() override
    {
        cout << "productA val:" << GetVal() << endl;
    }
};

class productB :public product
{
public:
    productB(int inum)
    {
        val = inum;
    };
    int GetVal() override
    {
        return val;
    }

    void CoutVal() override
    {
        cout << "productB val:" << GetVal() << endl;
    }
};

class productC :public product
{
public:
    productC(int inum)
    {
        val = inum;
    };
    int GetVal() override
    {
        return val;
    }

    void CoutVal() override
    {
        cout << "productC val:" << GetVal() << endl;
    }
};

class machine
{
public:
    machine() {};
    int val;
    virtual int GetVal() = 0;
    virtual void CoutVal() = 0;
};
class machineA :public machine
{
public:
    machineA(int inum)
    {
        val = inum;
    };
    int GetVal() override
    {
        return val;
    }
    void CoutVal() override
    {
        cout << "machineA val:" << GetVal() << endl;
    }
};
class machineB :public machine
{
public:
    machineB(int inum)
    {
        val = inum;
    };
    int GetVal() override
    {
        return val;
    }
    void CoutVal() override
    {
        cout << "machineB val:" << GetVal() << endl;
    }
};
class machineC :public machine
{
public:
    machineC(int inum)
    {
        val = inum;
    };
    int GetVal() override
    {
        return val;
    }
    void CoutVal() override
    {
        cout << "machineC val:" << GetVal() << endl;
    }
};

template  <class T>
class abstract_factory
{
public:
    virtual std::shared_ptr<T> CreatePrd(string istr) = 0;
    virtual std::shared_ptr<T> CreateMach(string istr) = 0;
};

template  <class T>
class prd_factory :public abstract_factory<T>
{
public:
    std::shared_ptr<T> CreatePrd(string istr) override
    {
        int param = 0;
        if (istr == "A")
        {
            param = 1;
            return std::make_shared<productA>(productA(param));
        }
        else if (istr == "B")
        {
            param = 2;
            return std::make_shared<productB>(productB(param));
        }
        else if (istr == "C")
        {
            param = 3;
            return std::make_shared<productC>(productC(param));
        }
        else
        {
            return nullptr;
        }
    }

    std::shared_ptr<T> CreateMach(string istr) override
    {
        return nullptr;
    };
};

template  <class T>
class mach_factory :public abstract_factory<T>
{
public:
    std::shared_ptr<T> CreatePrd(string istr) override
    {
        return nullptr;
    }

    std::shared_ptr<T> CreateMach(string istr) override
    {
        int param = 0;
        if (istr == "MA")
        {
            param = 4;
            return std::make_shared<machineA>(machineA(param));
        }
        else if (istr == "MB")
        {
            param = 5;
            return std::make_shared<machineB>(machineB(param));
        }
        else if (istr == "MC")
        {
            param = 6;
            return std::make_shared<machineC>(machineC(param));
        }
        else
        {
            return nullptr;
        }
    }
};

int main()
{
    string conf = "product";
    if (conf == "machine")
    {
        mach_factory<machine> FAC;
        auto pa = FAC.CreateMach("MA");
        auto pb = FAC.CreateMach("MB");
        auto pc = FAC.CreateMach("MC");

        if (pa && pb && pc)
        {
            pa->CoutVal();
            pb->CoutVal();
            pc->CoutVal();
        }
    }
    else if (conf == "product")
    {
        prd_factory<product> FAC;
        auto pa = FAC.CreatePrd("A");
        auto pb = FAC.CreatePrd("B");
        auto pc = FAC.CreatePrd("C");

        if (pa && pb && pc)
        {
            pa->CoutVal();
            pb->CoutVal();
            pc->CoutVal();
        }
    }

    getchar();

}

1.2单例模式

单例模式,顾名思义,就是只允许发生一次的模式

单例模式.png

具体来说,就是一个类能且仅能被实例化一次,通常用来实现一个特殊的全局类
我们常用的实现单例类的步骤是:
1.隐藏原有的构造函数
2.提供新的创建接口
3.在接口中判定是否已经有实现(单例判定)
4.考虑多线程的单例(double check+乱序执行优化)

我们还是给出单例的实例案例供参考:

class singleton {
private:
    singleton() {}

    static singleton *p;
    static mutex lock_;
public:
    singleton *instance();
    // 实现一个内嵌垃圾回收类
    class CGarbo
    {
    public:
        ~CGarbo()
        {
            if(singleton::p)
                delete singleton::p;
        }
    };
    // 所谓的垃圾回收,就是定义一个静态的类,类里面只有一个方法,这个方法检查singleton::p是否是空,不是空,执行delete
    // 由于是静态的方法,程序会自动的释放该对象,从而达到自动回收的机制。
    static CGarbo Garbo; // 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象
};

singleton *singleton::p = nullptr;
singleton::CGarbo Garbo;

singleton* singleton::instance() {
    //double check
    if (p == nullptr) {
        lock_guard<mutex> guard(lock_);
        if (p == nullptr)
            p = new singleton();
    }
    return p;
}

//考虑乱序执行
// method 1 operator new + placement new
singleton *instance() {
    if (p == nullptr) {
        lock_guard<mutex> guard(lock_);
        if (p == nullptr) {
            singleton *tmp = static_cast<singleton *>(operator new(sizeof(singleton)));
            new(tmp)singleton();
            p = tmp;
        }
    }
    return p;
}

placement new它的功能就是 在一个 已经分配好的空间上,调用构造函数,创建一个类。

new的功能分为****operator new**placement new****,我们做的就是为了防止这两步乱了,我们就自己去把它分开写就行了

1.3装饰模式

装饰模式,就像装修房子一样,本来都是一样的清水房,通过装修就可以赋予他们新的功能。

装饰器模式.png

它和抽象工厂的差异是,抽象工厂要添加功能,就需要继承并扩展功能(重新生成一个工厂)

而装饰类是一个施工队,你把产品给我,我来处理,更多的是一种聚合使用的方式扩展功能

同样,我们给出代码实例:

//抽象组件类-饮料(要生产的东西)
class Beverage
{
public:
	Beverage() :m_description("Unknown Beverage"){}
	virtual std::string getDescription(){ return m_description; }
	virtual double cost() = 0;
protected:
	std::string m_description;
};
//抽象装饰者类-调料,继承自饮料类(扩展原来工厂的类)
class CondimentDecorator :public Beverage
{
public:
	CondimentDecorator(Beverage* berverge) 
		:m_beverage(berverge){}
	virtual std::string getDescription() = 0;//定义成纯虚函数,是为了强制子类实例化时必须实现它。
protected:
	Beverage* m_beverage;
};
//三个具体组件(具体需要生产的类)
class DarkRoast :public Beverage
{
public:
	DarkRoast()	{
		m_description = "DarkRoast";
	}
	double cost(){
		return 2.99;
	}
};
class Espresso :public Beverage
{
public:
	Espresso(){
		m_description = "Espresso";
	}
	double cost(){
		return 1.99;
	}
};
class HouseBlend :public Beverage
{
public:
	HouseBlend(){
		m_description = "HouseBlend";
	}
	double cost(){
		return 0.89;
	}
};
//两个具体装饰者(两个施工队)
class Mocha :public CondimentDecorator
{
public: 
	Mocha(Beverage* beverage) :CondimentDecorator(beverage){}
	std::string getDescription(){
		return  m_beverage->getDescription() + " Mocha";
	}
	double cost(){
		return 0.2 + m_beverage->cost();
	}
};
class Milk :public CondimentDecorator
{
public:
	Milk(Beverage* beverage) :CondimentDecorator(beverage){}
	std::string getDescription(){
		return  m_beverage->getDescription() + " Milk";
	}
	double cost(){
		return 0.5 + m_beverage->cost();
	}
};
//测试代码
int main()
{
	//不加调料的Espresso
	Beverage* beverage = new Espresso();
	std::cout << beverage->getDescription() << " ¥" << beverage->cost() << std::endl;
	//加双倍摩卡和奶泡的DarkRoast
	Beverage* beverage2 = new DarkRoast();
	beverage2 = new Mocha(beverage2);//调用施工队,装饰产品
	beverage2 = new Mocha(beverage2);//调用施工队
	beverage2 = new Milk(beverage2);//调用施工队
	std::cout << beverage2->getDescription() << " ¥" << beverage2->cost() << std::endl;
	//加双倍奶泡的和一份摩卡的HouseBlend
	Beverage* beverage3 = new HouseBlend();
	beverage3 = new Mocha(beverage3);
	beverage3 = new Milk(beverage3);
	beverage3 = new Milk(beverage3);
	std::cout << beverage3->getDescription() << " ¥" << beverage3->cost() << std::endl;
	system("pause");
	delete beverage;
	delete beverage2;
	delete beverage3;
}

1.4原型模式

如果说抽象工厂是针对工厂的,装饰模式是针对产品的,他们都是针对创建类的类别、功能做文章

原型模式则是在优化创建的过程,加入我们需要大量生产一批产品,就需要大量使用工厂类的创建接口,但是每次我们都需要有一个工厂才能创建。

原型模式.png

如果,产品可以进行自我复制,就可以省掉创建工厂的步骤。

#include <iostream> 
using namespace std;  
/*抽象原型类*/
class Student
{
protected:
    int id;
    char name[10];
public:
    virtual Student* Clone() = 0;
    virtual void Show() = 0;
};
/*具体原型类*/
class StudentTypeA :public Student
{
public:
    StudentTypeA(const char* name_input){
        strcpy(name, name_input);
        this->id = 0;
        cout << "Construction....." << endl;
    }
    StudentTypeA(const StudentTypeA& other) {
        cout << "Copy Construction..." << endl;
        this->id = other.id;
        this->id++;
        strcpy(this->name, other.name);
    }
    virtual StudentTypeA* Clone() {
        StudentTypeA* tmp = new StudentTypeA(*this);
        return tmp;
    }
    void Show(){
        cout << "Student id == " << id << " name == " << name << endl;
    }
    ~StudentTypeA() {
        cout << "Deconstruction StudentTypeA" << endl;
    }
};
  
int main() 
{ 
  Student *student1 = new StudentTypeA("xiaoming"); 
  Student *student2 = student1->Clone(); //产品的自我复制,省掉了工厂
  Student *student3 = student2->Clone();   
  student1->Show(); 
  student2->Show(); 
  student3->Show();       
  return 0; 
} 

1.5生成器模式

以往我们建造产品,都是需要一次性创建一个完全的产品,而现实生活中,也会有不少产品是通过不同产品拼凑出来的。

如果说因为一点点的不一样就需要不同的工厂,也不太划算

所以我们也要学会生产半成品

生成器模式.png

同样,我们还是给出示例代码:

#ifndef  PRODUCT_H_
#define  PRODUCT_H_
#include <string>
#include <iostream>
// 产品类 车
class Car {
 public:
    Car() {}
    void set_car_tire(std::string t) {
        tire_ = t;
        std::cout << "set tire: " << tire_ << std::endl;
    }
    void set_car_steering_wheel(std::string sw) {
        steering_wheel_ = sw;
        std::cout << "set steering wheel: " << steering_wheel_ << std::endl;
    }
    void set_car_engine(std::string e) {
        engine_ = e;
        std::cout << "set engine: " << engine_ << std::endl;
    }

 private:
    std::string tire_;            // 轮胎
    std::string steering_wheel_;  // 方向盘
    std::string engine_;          // 发动机
};
#endif  // PRODUCT_H_

#ifndef  BUILDER_H_
#define  BUILDER_H_
#include "Product.h"
// 抽象建造者
class CarBuilder {
 public:
    Car getCar() {
        return car_;
    }
    // 抽象方法
    virtual void buildTire() = 0;
    virtual void buildSteeringWheel() = 0;
    virtual void buildEngine() = 0;
 protected:
    Car car_;
};
#endif  // BUILDER_H_

#ifndef CONCRETE_BUILDER_H_
#define CONCRETE_BUILDER_H_
#include "Builder.h"
// 具体建造者 奔驰
class BenzBuilder : public CarBuilder {
 public:
    // 具体实现方法
    void buildTire() override {
        car_.set_car_tire("benz_tire");
    }
    void buildSteeringWheel() override {
        car_.set_car_steering_wheel("benz_steering_wheel");
    }
    void buildEngine() override {
        car_.set_car_engine("benz_engine");
    }
};
// 具体建造者 奥迪
class AudiBuilder : public CarBuilder {
 public:
    // 具体实现方法
    void buildTire() override {
        car_.set_car_tire("audi_tire");
    }
    void buildSteeringWheel() override {
        car_.set_car_steering_wheel("audi_steering_wheel");
    }
    void buildEngine() override {
        car_.set_car_engine("audi_engine");
    }
};

#endif  // CONCRETE_BUILDER_H_

#ifndef  DIRECTOR_H_
#define  DIRECTOR_H_
#include "Builder.h"
class Director {
 public:
    Director() : builder_(nullptr) {}

    void set_builder(CarBuilder *cb) {
        builder_ = cb;
    }
    // 组装汽车
    Car ConstructCar() {
        builder_->buildTire();
        builder_->buildSteeringWheel();
        builder_->buildEngine();
        return builder_->getCar();
    }

 private:
    CarBuilder* builder_;
};

#endif  // DIRECTOR_H_

#include "Director.h"
#include "ConcreteBuilder.h"
int main() {
    // 抽象建造者(一般是动态确定的)
    CarBuilder* builder;
    // 指挥者
    Director* director = new Director();
    // 产品
    Car car;
    // 建造奔驰
    std::cout << "==========construct benz car==========" << std::endl;
    builder = new BenzBuilder();
    director->set_builder(builder);
    car = director->ConstructCar();
    delete builder;
    // 建造奥迪
    std::cout << "==========construct audi car==========" << std::endl;
    builder = new AudiBuilder();
    director->set_builder(builder);
    car = director->ConstructCar();
    delete builder;
    std::cout << "==========done==========" << std::endl;
    delete director;
}

1.6备忘录模式

之前我们聊到的创建模式都是一次性创建和复制相关的工作。

但是,加入一个产品有多个形态,我们想要恢复到之前的创建形态又该怎么办呢

打个快照呗。

备忘录模式.png

实现方式如下:

#ifndef MEMENTO_H_
#define MEMENTO_H_
#include <string>
// 备忘录类保存编辑器的过往状态
class Snapshot {
 public:
    Snapshot(std::string text, int x, int y, double width)
        : text_(text), cur_x_(x), cur_y_(y), selection_width_(width) {}
    std::string get_text() {
        return text_;
    }
    int get_cur_x() {
        return cur_x_;
    }
    int get_cur_y() {
        return cur_y_;
    }
    double get_selection_width() {
        return selection_width_;
    }
 private:
    const std::string text_;
    const int cur_x_;
    const int cur_y_;
    const double selection_width_;
};
#endif  // MEMENTO_H_

#ifndef ORIGINATOR_H_
#define ORIGINATOR_H_
#include <cstdio>
#include <string>
#include <memory>
#include "Memento.h"
// 原发器中包含了一些可能会随时间变化的重要数据
// 它还定义了在备忘录中保存自身状态的方法, 以及从备忘录中恢复状态的方法
class Editor {
 public:
    void setText(std::string text) {
        text_ = text;
    }
    void setCursor(int x, int y) {
        cur_x_ = x;
        cur_y_ = y;
    }
    void setSelectionWidth(double width) {
        selection_width_ = width;
    }
    // 在备忘录中保存当前的状态
    std::shared_ptr<Snapshot> createSnapshot() {
        // 备忘录是不可变的对象, 因此原发器会将自身状态作为参数传递给备忘录的构造函数
        auto res = std::make_shared<Snapshot>(text_, cur_x_, cur_y_, selection_width_);
        printf("创建编辑器快照成功, text:%s x:%d y:%d width:%.2f\n", text_.c_str(), cur_x_, cur_y_, selection_width_);
        return res;
    }
    void resotre(std::shared_ptr<Snapshot> sptr_snapshot) {
        text_ = sptr_snapshot->get_text();
        cur_x_ = sptr_snapshot->get_cur_x();
        cur_y_ = sptr_snapshot->get_cur_y();
        selection_width_ = sptr_snapshot->get_selection_width();
        printf("恢复编辑器状态成功, text:%s x:%d y:%d width:%.2f\n", text_.c_str(), cur_x_, cur_y_, selection_width_);
    }
 private:
    // 文本
    std::string text_;
    // 光标位置
    int cur_x_;
    int cur_y_;
    // 当前滚动条位置
    double selection_width_;
};
#endif  // ORIGINATOR_H_

#ifndef CARETAKER_H_
#define CARETAKER_H_
#include <memory>
#include "Memento.h"
#include "Originator.h"
class Command {
 public:
    explicit Command(Editor* e) : editor_(e) {}
    void makeBackup() {
        backup_ = editor_->createSnapshot();
    }
    void undo() {
        if (backup_) {
            editor_->resotre(backup_);
        }
    }
 private:
    Editor *editor_;
    std::shared_ptr<Snapshot> backup_;
};
#endif  // CARETAKER_H_

#include "Caretaker.h"
int main() {
    // 创建原发器和负责人
    Editor editor;
    Command command(&editor);
    // 定义初始状态
    editor.setText("TOMOCAT");
    editor.setCursor(21, 34);
    editor.setSelectionWidth(3.4);
    // 保存状态
    command.makeBackup();
    // 更改编辑器状态
    editor.setText("KKKK");
    editor.setCursor(111, 222);
    editor.setSelectionWidth(111.222);
    // 撤销
    command.undo();
    return 0;
}

2.层次型模式

2.1适配器模式

从这一节开始,我们不再仅仅关注一个类如何被创建的问题,而是着手于分层次复用代码。

首先,就介绍一个模式,适配器模式,没错,就是STL里面提到的那个适配器。

它的特点是原有一套核心的功能接口,但是我们需要稍微改动他,去适应新的业务。

所以,我们单独划分一个适配层,将原有的功能接口转接适配出去。这其实有一些类似于我们之前提到的装饰模式。

以下是UML和示例代码;

适配器模式.png

#ifndef CLIENT_INTERFACE_H_
#define CLIENT_INTERFACE_H_
// 圆钉: 客户端接口, 在C++中定义成抽象基类
class RoundPeg {
 public:
    RoundPeg() {}
    virtual int get_radius() = 0;
};
#endif  // CLIENT_INTERFACE_H_

#ifndef ADAPTER_H_
#define ADAPTER_H_
#include <cmath>
#include "Service.h"
#include "ClientInterface.h"
// 方钉适配器: 该适配器能让客户端将方钉放入圆孔中
class SquarePegAdapter : public RoundPeg {
 public:
    explicit SquarePegAdapter(SquarePeg* sp) : square_peg_(sp) {}
    int get_radius() override {
        return square_peg_->get_width() * sqrt(2) / 2;
    }
 private:
    SquarePeg* square_peg_;
};
#endif  // ADAPTER_H_

#ifndef SERVICE_H_
#define SERVICE_H_
// 方钉: 适配者类, 即和客户端不兼容的类
class SquarePeg {
 public:
    explicit SquarePeg(int w) : width_(w) {}
    int get_width() {
        return width_;
    }
 private:
    int width_;
};
#endif  // SERVICE_H_

#ifndef CLIENT_H_
#define CLIENT_H_
#include "ClientInterface.h"
// 圆孔: 客户端类
class RoundHole {
 public:
    explicit RoundHole(int r) : radius_(r) {}
    int get_radius() {
        return radius_;
    }
    bool isFit(RoundPeg* rp) {
        return radius_ >= rp->get_radius();
    }

 private:
    int radius_;
};
#endif  // CLIENT_H_

#include <iostream>
#include "Client.h"
#include "Adapter.h"
int main() {
    // 半径为10的圆孔
    RoundHole* hole = new RoundHole(10);
    // 半径分别为5和20的大小方钉 + 它们的适配器
    SquarePeg* samll_square_peg = new SquarePeg(5);
    SquarePeg* large_square_peg = new SquarePeg(20);
    SquarePegAdapter* small_square_peg_adapter = new SquarePegAdapter(samll_square_peg);
    SquarePegAdapter* large_square_peg_adapter = new SquarePegAdapter(large_square_peg);
    // hole->isFit(samll_square_peg);  // 编译报错
    // hole->isFit(large_square_peg);  / / 编译报错
    if (hole->isFit(small_square_peg_adapter)) {
        std::cout << "small square peg fits the hole" << std::endl;
    } else {
        std::cout << "small square peg don't fit the hole" << std::endl;
    }
    if (hole->isFit(large_square_peg_adapter)) {
        std::cout << "large square peg fits the hole" << std::endl;
    } else {
        std::cout << "large square peg don't fit the hole" << std::endl;
    }
}

2.2组合模式

组合模式是一种“伪设计模式”,他其实不太有“设计感”

简单来说,我们之前讨论的设计模式,他的各种生产、适配的类之间,一般是一种线性的关系或者是图的关系。

但是,世界上还有一种计算机很喜欢的关系,叫树形关系。

简单来说,我们有一颗多叉树,把父节点当做基类,子节点含有父节点的结构功能,但是叶子节点除外。叶子结点仅仅处理自己这一种情况。

以下是UML和示例代码:

组合模式.png

//节点的定义
class Component
{
public:
   virtual void Add(Component *cmpt) = 0;  //添加节点
   virtual void Remove(Component *cmpt) = 0;  //删除节点
   virtual void Operation() = 0;
   virtual ~Component(){}
};
 
//树节点
class Composite : public Component //既继承
{ 
private:   
    string name;
    list<Component*> elements;//又有组合,这就是设计模式惯用的手法
public:
    Composite(const string & s) : name(s) {}
    
    virtual void Add(Component* element) {
        elements.push_back(element);
    }
    virtual void Remove(Component* element){
        elements.remove(element);
    }
    
    virtual void Operation(){        
        //1.处理当前的节点            
        //2.处理当前节点的叶子节点,如果当前节点的叶子节点是树节点就循环调用
        for (auto &e : elements)
            e->Operation(); //多态调用 (这里是组合模式的精华)      
    }
}; 
//叶子节点
class Leaf : public Component
{
private:
    string name;
public:
    Leaf(string s) : name(s) {}
            
    virtual void Operation(){
        //处理当前节点
    }
    //注意:叶子节点没有添加和删除节点的功能,这里可以写一个空方法
};
 
//可以用了
//先写一个调用函数
void Show(Component & c)
{
    c.Operation();
}
 
int main()
{   	
    Component *pRoot = new Composite("班长");//根节点
 
    Component *pPart1 = new Composite("小组长1")//树节点
    pPart1->Add(new Leaf("小明"));
    pPart1->Add(new Leaf("小黄"));
 
    Component *pPart2 = new Composite("小组长2")//树节点
    pPart2->Add(new Leaf("小花"));
    pPart2->Add(new Leaf("小美"));
 
    pRoot->Add(pPart1);
    pRoot->Add(pPart2);
 
    
    Show(pRoot);//从根节点开始展示
    Show(pPart2);//展示其它节点也没问题
   
   return 0;
}

2.3桥接模式

咱们之前的层次模式都是一个大类里面,或者是有父子关系的树状结构里面。

而不同功能类之间,要想好好合作,生一个有父母有点的孩子,就需要爱情的桥梁。

那怎么实现呢,首先,要提取父母的基因(对类进行抽象),抽象不同的类组合成一个大的抽象类

然后对它进行实现,或者进行多重实现,具体UML和实例代码如下:

桥接,模式.png

#ifndef ABSTRACTION_H_
#define ABSTRACTION_H_
#include <string>
#include "Implementation.h"
// 抽象类: Pen
class Pen {
 public:
    virtual void draw(std::string name) = 0;
    void set_color(Color* color) {
        color_ = color;
    }
 protected:
    Color* color_;
};
#endif  // ABSTRACTION_H_

#ifndef REFINED_ABSTRACTION_H_
#define REFINED_ABSTRACTION_H_

#include <string>
#include "Abstraction.h"

// 精确抽象类: BigPen
class BigPen : public Pen {
 public:
    void draw(std::string name) {
        std::string pen_type = "大号钢笔绘制";
        color_->bepaint(pen_type, name);
    }
};

// 精确抽象类: SmallPencil
class SmallPencil : public Pen {
 public:
    void draw(std::string name) {
        std::string pen_type = "小号铅笔绘制";
        color_->bepaint(pen_type, name);
    }
};

#endif  // REFINED_ABSTRACTION_H_

#ifndef IMPLEMENTATION_H_
#define IMPLEMENTATION_H_

#include <string>
#include <iostream>

// 实现类接口: 颜色
class Color {
 public:
    virtual void bepaint(std::string pen_type, std::string name) = 0;
};

#endif  // IMPLEMENTATION_H_

#ifndef CONCRETE_IMPLEMENTATION_H_
#define CONCRETE_IMPLEMENTATION_H_

#include <string>
#include "Implementation.h"

// 具体实现类: Red
class Red : public Color {
 public:
    void bepaint(std::string pen_type, std::string name) override {
        std::cout << pen_type << "红色的" << name << "." << std::endl;
    }
};

// 具体实现类: Green
class Green : public Color {
 public:
    void bepaint(std::string pen_type, std::string name) override {
        std::cout << pen_type << "绿色的" << name << "." << std::endl;
    }
};


#endif  // CONCRETE_IMPLEMENTATION_H_

#include "ConcreteImplementation.h"
#include "RefinedAbstraction.h"

int main() {
    // 客户端根据运行时参数获取对应的Color和Pen
    Color* color = new Red();
    Pen* pen = new SmallPencil();

    pen->set_color(color);
    pen->draw("太阳");

    delete color;
    delete pen;
}

3.行为型模式

3.1模板方法

从这里开始,我们已经经历了创建、分层的设计模式,这一次,我们从类的行为本身出发进行设计模式的归纳。

首先要说的就是模板方法。

模板方法简单来说就是定义一个用于继承的方法,然后把方法拆解为不同的小块,这些小块是可以进行重写的。通过重写这些小块,我们就可以重新利用模板方法实现功能。

这种方式既可以保留调用的一致性,也可以最大程度保留原有的逻辑。

模板方法.png

//程序库开发人员
class Library {
public:
	void Step1() {
		//...
	}
	void Step3() {
		//...
	}
	void Step5() {
		//...
	}
};

//应用程序开发人员
class Application {
public:
	bool Step2() {
		//...
	}
	void Step4() {
		//...
	}
};

int main()
{
	Library lib;
	Application app;
	lib.Step1();
	if (app.Step2()) {
		lib.Step3();
	}
	for (int i = 0; i < 4; i++) {
		app.Step4();
	}
	lib.Step5();
}

 //程序库开发人员
class Library {
public:
    //稳定 template method
    void Run() {
        Step1();
        if (Step2()) { //支持变化 ==> 虚函数的多态调用
            Step3();
        }
        for (int i = 0; i < 4; i++) {
            Step4(); //支持变化 ==> 虚函数的多态调用
        }
        Step5();
    }
    virtual ~Library() { }
protected:
    void Step1() { //稳定
        //.....
    }
    void Step3() {//稳定
        //.....
    }
    void Step5() { //稳定
        //.....
    }
    virtual bool Step2() = 0;//变化
    virtual void Step4() = 0; //变化
};

//应用程序开发人员
class Application : public Library {
protected:
    virtual bool Step2() {
        //... 子类重写实现
    }
    virtual void Step4() {
        //... 子类重写实现
    }
};

int main()
{
    Library* pLib = new Application();
    pLib->Run();
    delete pLib;
}

3.2观察者模式

观察者模式,这是一个十分有用的模式,可以说不同类的通信很大程度都依赖这个模式。

我们将类分为两种,

一种是被观测者,它在自身发生某一些改动时,大叫一声通知其他人;

一种是观察者,它听见被观测者的叫喊时做出反应。

当然,我们需要给他们都提供一个抽象类

具体的UML和实例代码如下:

观察者模式.png

#include <iostream>
#include <string>
#include <list>
using namespace std;
 
class Subject;
 
//抽象观察者
class Observer
{
protected:
	string name;
	Subject* sub;
public:
	Observer(string name, Subject* sub)
	{
		this->name = name;
		this->sub = sub;
	}
	virtual void update() = 0;
};
 
//具体的观察者: 看股票的
class StockObserver :public Observer
{
public:
	StockObserver(string name, Subject* sub) :Observer(name, sub)
	{
	}
	void update();
};
 
//具体的观察者:看NBA的
class NBAObserver :public Observer
{
public:
	NBAObserver(string name, Subject* sub) :Observer(name, sub)
	{
	}
	void update();
};
 
//抽象通知者
class Subject
{
protected:
	list<Observer*> observers;	//观察者列表
public:
	string action;
	virtual void attach(Observer*) = 0;
	virtual void detach(Observer*) = 0;
	virtual void notify() = 0;
};
 
//具体通知者:秘书
class Secretary :public Subject
{
public:
	void attach(Observer* observer)
	{
		observers.push_back(observer);
	}
 
	//删除观察者
	void detach(Observer* observer)
	{
		for (auto iter = observers.begin(); iter != observers.end(); )
		{
			if ((*iter) == observer)
			{
				observers.erase(iter);
			}
			++iter;
		}
	}
 
	//通知观察者
	void notify()
	{
		for (auto iter = observers.begin(); iter != observers.end(); iter++)
		{
			(*iter)->update();
		}
	}
};
 
#include "stdafx.h"
#include "Observer.h"
 
void StockObserver::update()
{
	cout << name << " 股票组: 收到消息:" << sub->action << endl;
	if (sub->action == "总监来了!")
	{
		cout << "股票组: 我马上关闭股票" << endl;
	}
}
 
void NBAObserver::update()
{
	cout << name << " NBA组: 收到消息:" << sub->action << endl;
	if (sub->action == "总监来了!")
	{
		cout << "NBA组: 我马上关闭NBA" << endl;
	}
}
 
int main()
{
	Subject* se = new Secretary();	//创建观察者    //被观察的对象
	Observer* o1 = new NBAObserver("NBA001", se);
	Observer* o2 = new NBAObserver("NBA002", se);
	Observer* lm = new StockObserver("股票A", se);
	
	se->attach(o1);	//加入观察队列
	se->attach(o2);
	se->attach(lm);
	
	se->action = "出去开会了!";	//事件
	se->notify();
	cout << endl;
 
	se->action = "总监来了";
	se->notify();
	return 0;
}

3.3状态模式

在讲述状态模式之前,我们已经提到了一种模式:备忘录模式

我们说备忘录模式将会记录当前状态和前一个、后一个状态,进行创建过程中的撤销重做

但是,这样局限的使用场景显然是不够的。我们需要在更多的时候使用更多的状态,甚至让不同的状态拥有不同的行为,这里就需要使用状态模式了。同样,状态可以作为一种抽象,继承自抽象的类执行不同状态的方法。

状态模式.png

// 此文件包含 "main" 函数。程序执行将在此处开始并结束。 
// 参考大话设计模式 - 状态模式
 #include <iostream>
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif 
// 状态模式:存在多种状态,用if else逻辑较为繁琐时,可采用状态模式进行管控
// 注意:内存泄露问题
using namespace std;
class Work;
class FornoonState; 
class State {
public:
	virtual void writeProgram(Work* work) = 0;
};
class Work {
public:
	Work();
	~Work() {
		SAFE_DELETE(state_);
	} 
	void setHour(int hour) {
		hour_ = hour;
	}
	int getHour() {
		return hour_;
	}
 	void setFinish(bool finish) {
		finish_ = finish;
	}
	int getFinish() {
		return finish_;
	}
 	// 此处注意内存泄露
	void setState(State* state) {
		SAFE_DELETE(state_);
		state_ = state;
	}
	void getCurrentState() {
		state_->writeProgram(this);
	}
 private:
	int hour_ = 0;
	bool finish_ = false;
	State* state_ = nullptr;
};
 class SleeptimeState : public State {
public:
	void writeProgram(Work* work) {
		cout << "time: " << work->getHour() << ", can not work ,need sleep" << endl;
	}
};
 class GohomeState : public State {
public:
	void writeProgram(Work* work) {
		work->setFinish(true);
	}
};
 class NigthtimeState : public State {
public:
	void writeProgram(Work* work) {
		if (work->getFinish()) {
			cout << "time: " << work->getHour() << ", work done, go home" << endl;
			work->setState(new GohomeState());
		}
		else {
			if (work->getHour() < 21) {
				cout << "time: " << work->getHour() << ", work very tired." << endl;
			}
			else {
				work->setState(new SleeptimeState());
				work->getCurrentState();
			}
		}
	}
};
 
class AfternoonState : public State {
public:
	void writeProgram(Work* work) {
		if (work->getHour() < 19) {
			cout << "time: " << work->getHour() << ", work tired." << endl;
		}
		else {
			work->setState(new NigthtimeState());
			work->getCurrentState();
		}
	}
};
 class NoontimeState : public State {
public:
	void writeProgram(Work* work) {
		if (work->getHour() < 14) {
			cout << "time: " << work->getHour() << ", work hungry." << endl;
		}
		else {
			work->setState(new AfternoonState());
			work->getCurrentState();
		}
	}
};
 class FornoonState : public State {
public:
	void writeProgram(Work* work) {
		if (work->getHour() < 12) {
			cout << "time: " << work->getHour() << ", work wonderful." << endl;
		} else {
			work->setState(new NoontimeState());
			work->getCurrentState();
		}
	}
};

Work::Work() {
	state_ = new FornoonState();
}
 
int main()
{
	Work* work = new Work();
 	work->setHour(8);
	work->getCurrentState();
 	work->setHour(9);
	work->getCurrentState();
 	work->setHour(12);
	work->getCurrentState();
 	work->setHour(15);
	work->getCurrentState();
 	work->setHour(17);
	work->getCurrentState();
 	work->setHour(19);
	work->getCurrentState();
	work->setFinish(true);
	work->getCurrentState();
	work->setHour(21);
	work->getCurrentState();
	SAFE_DELETE(work);
	return 0;
}
 
 

3.4命令模式

每一条命令可以被理解为一条指令(具体指令实现继承于抽象的指令),用户通过各种输入来启动指令,指令启动执行完成之后,将结果返回给一个类,最总控制权交还给用户。

命令模式.png

#include <iostream>
using namespace std;
#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }
class Receiver
{
public:
     void Action()
     {
          cout<<"Receiver->Action"<<endl;
     }
};
class Command
{
public:
     virtual void Execute() = 0;
};
class ConcreteCommand : public Command
{
public:
     ConcreteCommand(Receiver *pReceiver) : m_pReceiver(pReceiver){}
     void Execute()
     {
         m_pReceiver->Action();
     }
private:
     Receiver *m_pReceiver;
};
 class Invoker
{
public:
     Invoker(Command *pCommand) : m_pCommand(pCommand){}
     void Invoke() {
          m_pCommand->Execute();
     }
private:
    Command *m_pCommand;

};
int main()
{
     Receiver *pReceiver = new Receiver();
     Command *pCommand = new ConcreteCommand(pReceiver);
     Invoker *pInvoker = new Invoker(pCommand);
     pInvoker->Invoke();
     SAFE_DELETE(pInvoker);
     SAFE_DELETE(pCommand);
     SAFE_DELETE(pReceiver);
     return 0;
}


4.结构型模式

4.1代理模式

如果我们每次操作一个类,都需要直接地调用它的方法,那这可能是繁琐而且没有设计感的。

所以,我们可以将需要操作的类中同事放入真正的类和一个代理类,每次我们想要操作真正的类,都可以通过代理。这样干净又卫生,就像科学上网一样。

代理模式.png

#ifndef SERVICE_INTERFACE_H_
#define SERVICE_INTERFACE_H_

#include <string>

// 远程服务接口
class ThirdPartyTVLib {
 public:
    virtual std::string listVideos() = 0;
    virtual std::string getVideoInfo(int id) = 0;
};

#endif  // SERVICE_INTERFACE_H_


#ifndef SERVICE_H_
#define SERVICE_H_

#include <string>
#include "ServiceInterface.h"

// 视频下载类
// 该类的方法可以向远程视频后端服务请求信息, 请求速度取决于用户和服务器的网络状况
// 如果同时发送大量请求, 即使所请求的信息一模一样, 程序的速度依然会变慢
class ThirdPartyTVClass : public ThirdPartyTVLib {
 public:
    std::string listVideos() override {
        // 向远程视频后端服务发送一个API请求获取视频信息, 这里忽略实现
        return "video list";
    }

    std::string getVideoInfo(int id) override {
        // 向远程视频后端服务发送一个API请求获取某个视频的元数据, 这里忽略实现
        return "video info";
    }
};

#endif  //  SERVICE_H_

#ifndef PROXY_H_
#define PROXY_H_

#include <string>
#include "ServiceInterface.h"

// 为了节省网络带宽, 我们可以将请求缓存下来并保存一段时间
// 当代理类接受到真实请求后才会将其委派给服务对象
class CachedTVClass : public ThirdPartyTVLib {
 public:
    explicit CachedTVClass(ThirdPartyTVLib* service) : service_(service), need_reset_(false), list_cache_(""), video_cache_("") {}
    void reset() {
        need_reset_ = true;
    }

    std::string listVideos() override {
        if (list_cache_ == "" || need_reset_) {
            list_cache_ = service_->listVideos();
        }
        return list_cache_;
    }

    std::string getVideoInfo(int id) override {
        if (video_cache_ == "" || need_reset_) {
            video_cache_ = service_->getVideoInfo(id);
        }
        return video_cache_;
    }

 private:
    ThirdPartyTVLib* service_;
    std::string list_cache_;
    std::string video_cache_;
    bool need_reset_;
};

#endif  // PROXY_H_

#ifndef CLIENT_H_
#define CLIENT_H_

#include <string>
#include <cstdio>
#include "Service.h"

// 之前直接与服务对象交互的 GUI 类不需要改变, 前提是它仅通过接口与服务对象交互。
// 我们可以安全地传递一个代理对象来代替真实服务对象, 因为它们都实现了相同的接口。
class TVManager {
 public:
    explicit TVManager(ThirdPartyTVLib* s) : service_(s) {}
    void renderVideoPage(int id) {
        std::string video_info = service_->getVideoInfo(id);
        // 渲染视频页面, 这里忽略实现
        printf("渲染视频页面: %s\n", video_info.c_str());
        return;
    }
    void renderListPanel() {
        std::string videos = service_->listVideos();
        // 渲染视频缩略图列表, 这里忽略实现
        printf("渲染视频缩略图列表: %s\n", videos.c_str());
        return;
    }

 private:
    ThirdPartyTVLib* service_;
};

#endif  // CLIENT_H_

#include "Client.h"
#include "Service.h"
#include "Proxy.h"

int main() {
    ThirdPartyTVClass* aTVService = new ThirdPartyTVClass();
    CachedTVClass* aTVProxy = new CachedTVClass(aTVService);
    TVManager* manager = new TVManager(aTVProxy);

    manager->renderVideoPage(1);
    manager->renderListPanel();

    delete aTVService;
    delete aTVProxy;
    delete manager;
}

4.2中介模式

这是最不值得讲的一个模式。简而言之,采用一个中介对象来封装一系列的对象交互。使得各个对象不需要显式的相互引用,达到解耦的效果。

就像名字一样,需要一个中介。

中介模式.png

#include <iostream>
#include <string>
using namespace std;
 
class HousePerson;
class BuyHousePerson;
class SellHousePerson;
 
//抽象中介类
class Mediator{
public:
	virtual void sendMessage(string msg, HousePerson *p) = 0;
};
 
//抽象炒房客
class HousePerson{
public:
	HousePerson(Mediator *mediator)
	{
		m_mediator = mediator;
	}
protected:
	Mediator *m_mediator;
};
 
//买房的人
class BuyHousePerson :public HousePerson
{
public:
	BuyHousePerson(Mediator *mediator) :HousePerson(mediator){}
	void sendMsg(string msg)
	{
		m_mediator->sendMessage(msg,this);
	}
	void notify(string msg)
	{
		cout << "买房者得到消息:" << msg << endl;
	}
};
 
//卖房的人
class SellHousePerson :public HousePerson
{
public:
	SellHousePerson(Mediator *mediator) :HousePerson(mediator){}
	void sendMsg(string msg)
	{
		m_mediator->sendMessage(msg, this);
	}
	void notify(string msg)
	{
		cout << "卖-房者得到消息:" << msg << endl;
	}
};
 
//具体中介类
class ConcreteMediator :public Mediator
{
public:
	void sendMessage(string msg, HousePerson *p)
	{
		if (p == bh)
		{
			sh->notify(msg);
		}
		else
		{
			bh->notify(msg);
		}
	}
 
public:
	BuyHousePerson *bh;
	SellHousePerson *sh;
};
 
//客户端
int main()
{
	ConcreteMediator *pM = new ConcreteMediator;
	BuyHousePerson *pBh = new BuyHousePerson(pM);
	SellHousePerson* pSh = new SellHousePerson(pM);
 
	pM->bh = pBh;
	pM->sh = pSh;
 
	pBh->sendMsg("卖不卖,一口价780W");
	pSh->sendMsg("不卖,至少800W!");
 
	if (pM)
	{
		delete pM;
		pM = nullptr;
	}
	if (pBh)
	{
		delete pBh;
		pBh = nullptr;
	}
	if (pSh)
	{
		delete pSh;
		pSh = nullptr;
	}
 
	return 0;
}

4.3享元模式

我们早就说过,设计模式的一大功能便是尽可能的复用代码,从建造到调用都是。

但是,我们往往会隔离不同的独立类,或者说,有限的复用独立类之间的代码。但是,有时候,我们的业务需求是轻微改动一个类,并要求它在逻辑上是独立运行的。

这个时候,我们就需要复用代码大师,享元模式了。

享元模式其实原理不难,在共同的父类中,实现需要公用的代码,需要时直接调用。
享元模式.png

class Flyweight
{
public:
	virtual void Operation() = 0;
};
class ConcreteFlyweight : public Flyweight
{
public:
	void Operation() {};
};
class UnshareConcreteFlyweight : public Flyweight
{
public:
	void Operation() {};
};
 
class FlyweightFactory
{
public:
	FlyweightFactory() { confly = nullptr; uncfly = nullptr; }
	~FlyweightFactory() { delete confly; delete uncfly; }
	void GetFlyweight()
	{
		if (confly == nullptr)
			confly = new ConcreteFlyweight();
		confly->Operation();
 
		if (uncfly == nullptr)
			uncfly = new UnshareConcreteFlyweight();
		uncfly->Operation();
	}
private:
	Flyweight* confly;
	Flyweight* uncfly;
};
int main()
{
	FlyweightFactory flyfac;
	flyfac.GetFlyweight();
	return 0;
}

参考资料:

《大话设计模式》
《设计模式 可复用面向对象软件的基础》

Q.E.D.


世界上只有一种英雄主义