《大话设计模式》一书中提到 24 种设计模式，这 24 种设计模式没必要面面俱到，但一定要深入了解其中的几种，最好结合自己在实际开发过程中的例子进行深入的了解。

### 设计模式有 6 大设计原则：

- **单一职责原则** ：就一个类而言，应该仅有一个引起它变化的原因。
- **开放封闭原则** ：软件实体可以扩展，但是不可修改。即面对需求，对程序的改动可以通过增加代码来完成，但是不能改动现有的代码。
- **里氏代换原则** ：一个软件实体如果使用的是一个基类，那么一定适用于其派生类。即在软件中，把基类替换成派生类，程序的行为没有变化。
- **依赖倒转原则** ：抽象不应该依赖细节，细节应该依赖抽象。即针对接口编程，不要对实现编程。
- **迪米特原则** ：如果两个类不直接通信，那么这两个类就不应当发生直接的相互作用。如果一个类需要调用另一个类的某个方法的话，可以通过第三个类转发这个调用。
- **接口隔离原则** ：每个接口中不存在派生类用不到却必须实现的方法，如果不然，就要将接口拆分，使用多个隔离的接口。

### 设计模式分为三类：

**创造型模式** ：单例模式、工厂模式、建造者模式、原型模式

**结构型模式** ：适配器模式、桥接模式、外观模式、组合模式、装饰模式、享元模式、代理模式

**行为型模式** ：责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式。

### 介绍常见的几种设计模式：

**单例模式：**保证一个类仅有一个实例，并提供一个访问它的全局访问点。
**工厂模式：**包括简单工厂模式、抽象工厂模式、工厂方法模式
**简单工厂模式：**主要用于创建对象。用一个工厂来根据输入的条件产生不同的类，然后根据不同类的虚函数得到不同的结果。
**抽象工厂模式：**定义了一个创建一系列相关或相互依赖的接口，而无需指定他们的具体类。
**观察者模式：**定义了一种一对多的关系，让多个观察对象同时监听一个主题对象，主题对象发生变化时，会通知所有的观察者，使他们能够更新自己。
**装饰模式：**动态地给一个对象添加一些额外的职责，就增加功能来说，装饰模式比生成派生类更为灵活。

### 1、说说面对对象中的设计原则

SRP（Single Responsibility Principle）：**单一职责原则**，就是说一个类只提供一种功能和仅有一个引起它变化的因素。

OCP（Open Close Principle）：**开放封闭原则**，就是对一个类来说，对它的内部修改是封闭的，对它的扩展是开放的。

DIP（Dependence Inversion Principle）：**依赖倒置原则**，就是程序依赖于抽象，而不依赖于实现，它的主要目的是为了降低耦合性，它一般通过反射和配置文件来实现的。

LSP（Liskov Substitution Principle）：**里氏替换原则**，就是基类出现的地方，通过它的子类也完全可以实现这个功能

ISP（Interface Segregation Principle）：**接口隔离原则**，建立单一接口，不要建立庞大臃肿的接口，尽量细化接口，接口中的方法尽量少。也就是说，我们要为各个类建立专用的接口，而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。

CRP（Composite Reuse Principle）：**合成复用原则**，多用组合设计类，少用继承。

### 2、单一职责原则和接口隔离原则的区别

- 单一职责原则注重的是职责；而接口隔离原则注重对接口依赖的隔离。 

- 单一职责原则主要是约束类，其次才是接口和方法，它针对的是程序中的实现和细节； 而接口隔离原则主要约束接口，主要针对抽象，针对程序整体框架的构建。 

### 3、单例模式

有两种懒汉和饿汉：

饿汉：饿了就饥不择食了，所以在单例类定义的时候就进行实例化。

懒汉：顾名思义，不到万不得已就不会去实例化类，也就是在第一次用到的类实例的时候才会去实例化。

**饿汉模式（线程安全）：**

在最开始的时候静态对象就已经创建完成，设计方法是类中包含一个静态成员指针，该指针指向该类的一个对象，提供一个公有的静态成员方法，返回该对象指针，为了使得对象唯一，构造函数设为私有。

```c++
#include <iostream>
#include <algorithm>
using namespace std;

class SingleInstance {
public:
    static SingleInstance* GetInstance() {
        static SingleInstance ins;
        return &ins;
    }
    ~SingleInstance(){};
private:
    //涉及到创建对象的函数都设置为private
    SingleInstance() {  std::cout<<"SingleInstance() 饿汉"<<std::endl;   }
    SingleInstance(const SingleInstance& other) {};
    SingleInstance& operator=(const SingleInstance& other) {return *this;}
};

int main(){
    //因为不能创建对象所以通过静态成员函数的方法返回静态成员变量
    SingleInstance* ins = SingleInstance::GetInstance();
    return 0;
}
//输出 SingleInstance() 饿汉
```

**懒汉模式（线程安全需要加锁）：**

尽可能的晚的创建这个对象的实例，即在单例类第一次被引用的时候就将自己初始化，C++ 很多地方都有类型的思想，比如写时拷贝，晚绑定等。

```c++
#include <pthread.h>
#include <iostream>
#include <algorithm>
using namespace std;

class SingleInstance {
public:
    static SingleInstance* GetInstance() {
        if (ins == nullptr) {
            pthread_mutex_lock(&mutex);
            if (ins == nullptr) {
                ins = new SingleInstance();
            }
            pthread_mutex_unlock(&mutex);
        }
        return ins;
    }
    ~SingleInstance(){};
    //互斥锁
    static pthread_mutex_t mutex;
private:
    //涉及到创建对象的函数都设置为private
    SingleInstance() {  std::cout<<"SingleInstance() 懒汉"<<std::endl;   }
    SingleInstance(const SingleInstance& other) {};
    SingleInstance& operator=(const SingleInstance& other) {	return *this;	}
    //静态成员
    static SingleInstance* ins;
};

//懒汉式 静态变量需要定义
SingleInstance* SingleInstance::ins = nullptr;
pthread_mutex_t SingleInstance::mutex;

int main(){
    //因为不能创建对象所以通过静态成员函数的方法返回静态成员变量
    SingleInstance* ins = SingleInstance::GetInstance();
    delete ins;
    return 0;
}
//输出 SingleInstance() 懒汉
```

单例模式的适用场景

（1）系统只需要一个实例对象，或者考虑到资源消耗的太大而只允许创建一个对象。

（2）客户调用类的单个实例只允许使用一个公共访问点，除了该访问点之外不允许通过其它方式访问该实例（就是共有的静态方法）。

### 4、工厂模式

简单工厂模式：

就是建立一个工厂类，对实现了同一接口的一些类进行实例的创建。简单工厂模式的实质是由一个工厂类根据传入的参数，动态决定应该创建哪一个产品类（这些产品类继承自一个父类或接口）的实例。

```c++
#include <iostream>
#include <pthread.h>
using namespace std;

//产品类（抽象类，不能实例化）
class Product{
public:
    Product(){};
    virtual void show()=0;  //纯虚函数
};

class productA : public Product{
public:
    productA(){};
    void show(){ std::cout << "product A create!" << std::endl; };
    ~productA(){};
};

class productB : public Product{
public:
    productB(){};
    void show(){ std::cout << "product B create!" << std::endl; };
    ~productB(){};
};

class simpleFactory{ // 工厂类
public:
    simpleFactory(){};
    Product* product(const string str){
        if (str == "productA")
            return new productA();
        if (str == "productB")
           return new productB();
        return NULL;
    };
};

int main(){
    simpleFactory obj; // 创建工厂
    Product* pro; // 创建产品
    pro = obj.product("productA");
    pro->show(); // product A create!
    delete pro;

    pro = obj.product("productB");
    pro->show(); // product B create!
    delete pro;
    return 0;
}
```

工厂模式目的就是代码解耦，如果我们不采用工厂模式，如果要创建产品 A、B，通常做法采用用 switch...case语句，那么想一想后期添加更多的产品进来，我们不是要添加更多的 switch...case 吗？这样就很麻烦，而且也不符合设计模式中的**开放封闭原则**。

为了进一步解耦，在简单工厂的基础上发展出了抽象工厂模式，即连工厂都抽象出来，实现了进一步代码解耦。

代码如下：

```c++
#include <iostream>
#include <pthread.h>
using namespace std;

//产品类（抽象类，不能实例化）
class Product{
public:
    Product(){}
    virtual void show()=0;  //纯虚函数
};

class Factory{//抽象类
public:
    virtual Product* CreateProduct()=0;//纯虚函数
};
//产品A
class ProductA:public Product{
public:
    ProductA(){}
    void show(){ std::cout<<"product A create!"<<std::endl; };
};

//产品B
class ProductB:public Product{
public:
    ProductB(){}
    void show(){ std::cout<<"product B create!"<<std::endl; };
};

//工厂类A，只生产A产品
class FactorA: public Factory{
public:
    Product* CreateProduct(){
        Product* product_ = nullptr;
        product_ = new ProductA();
        return product_;
    }
};
//工厂类B，只生产B产品
class FactorB: public Factory{
public:
    Product* CreateProduct(){
        Product* product_ = nullptr;
        product_ = new ProductB();
        return product_;
    }
};

int main(){
    Product* product_ = nullptr;
    auto MyFactoryA = new FactorA();
    product_ = MyFactoryA->CreateProduct();// 调用产品A的工厂来生产A产品
    product_->show();
    delete product_;

    auto MyFactoryB=new FactorB();
    product_ = MyFactoryB->CreateProduct();// 调用产品B的工厂来生产B产品
    product_->show();
    delete product_;

    return 0;
}
//输出 
//product A create! product B create!
```

### 5、观察者模式

**观察者模式：**定义一种一（被观察类）对多（观察类）的关系，让多个观察对象同时监听一个被观察对象，被观察对象状态发生变化时，会通知所有的观察对象，使他们能够更新自己的状态。

观察者模式中存在两种角色：

**观察者：**内部包含被观察者对象，当被观察者对象的状态发生变化时，更新自己的状态。（接收通知更新状态）
**被观察者：**内部包含了所有观察者对象，当状态发生变化时通知所有的观察者更新自己的状态。（发送通知）
应用场景：

当一个对象的改变需要同时改变其他对象，且不知道具体有多少对象有待改变时，应该考虑使用观察者模式；
一个抽象模型有两个方面，其中一方面依赖于另一方面，这时可以用观察者模式将这两者封装在独立的对象中使它们各自独立地改变和复用。
实现方式：

```c++
#include <iostream>
#include <string>
#include <list>
using namespace std;

class Subject;
//观察者 基类 （内部实例化了被观察者的对象sub）
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();
};

class NBAObserver : public Observer {
public:
    NBAObserver(string name, Subject *sub) : Observer(name, sub){}
    void update();
};
//被观察者 基类 （内部存放了所有的观察者对象，以便状态发生变化时，给观察者发通知）
class Subject {
protected:
    std::list<Observer *> observers;
public:
    string action; //被观察者对象的状态
    virtual void attach(Observer *) = 0;
    virtual void detach(Observer *) = 0;
    virtual void notify() = 0;
};

class Secretary : public Subject {
    void attach(Observer *observer) {
        observers.push_back(observer);
    }
    void detach(Observer *observer) {
        list<Observer *>::iterator iter = observers.begin();
        while (iter != observers.end()) {
            if ((*iter) == observer) {
                observers.erase(iter);
                return;
            }
            ++iter;
        }
    }
    void notify() {
        list<Observer *>::iterator iter = observers.begin();
        while (iter != observers.end()) {
            (*iter)->update();
            ++iter;
        }
    }
};

void StockObserver::update() {
    cout << name << " 收到消息：" << sub->action << endl;
    if (sub->action == "老板来了!") {
        cout << "我马上关闭股票，装做很认真工作的样子！" << endl;
    }
}

void NBAObserver::update() {
    cout << name << " 收到消息：" << sub->action << endl;
    if (sub->action == "老板来了!") {
        cout << "我马上关闭 NBA，装做很认真工作的样子！" << endl;
    }
}

int main()
{
    Subject *BOSS = new Secretary();
    Observer *xa = new NBAObserver("xa", BOSS);
    Observer *xb = new NBAObserver("xb", BOSS);
    Observer *xc = new StockObserver("xc", BOSS);

    BOSS->attach(xz);
    BOSS->attach(xb);
    BOSS->attach(xc);

    BOSS->action = "去吃饭了！";
    BOSS->notify();
    cout << endl;
    BOSS->action = "老板来了!";
    BOSS->notify();
    return 0;
}
//输出 
//product A create! product B create!
```

### 6、装饰器模式

装饰器模式（Decorator Pattern）允许向一个现有的对象添加新的功能，**同时又不改变其结构**。

这种类型的设计模式属于结构型模式，它是作为现有的类的一个包装。

代码没有改变 Car 类的内部结构，还为其增加了新的功能，这就是装饰器模式的作用。

```c++
#include <iostream>
#include <list>
#include <memory>
using namespace std;

//抽象构件类 Transform (变形金刚)
class Transform{
public:
    virtual void move() = 0;
}; 

//具体构件类Car
class Car : public Transform{
public:
    Car(){
        std::cout << "变形金刚是一辆车！" << endl;
    }
    void move(){
        std::cout << "在陆地上移动。" << endl;
    }
}; 

//抽象装饰类
class Changer : public Transform{
public:
    Changer(shared_ptr<Transform> transform){
        this->transform = transform;
    }
    void move(){
        transform->move();
    }
private:
    shared_ptr<Transform> transform; 
}; 

//具体装饰类Robot
class Robot : public Changer{
public:
    Robot(shared_ptr<Transform> transform) : Changer(transform){
        std::cout << "变成机器人!" << std::endl;
    }

    void say(){
        std::cout << "说话!" << std::endl;
    }
}; 

//具体装饰类AirPlane
class Airplane : public Changer{
public:
    Airplane(shared_ptr<Transform> transform) : Changer(transform){
        std::cout << "变成飞机!" << std::endl;
    }

    void say(){
        std::cout << "在天空飞翔!" << std::endl;
    }    
}; 

int main(void){
    shared_ptr<Transform> camaro = make_shared<Car>();
    camaro->move();
    std::cout << "--------------" << endl;
    shared_ptr<Robot> bumblebee = make_shared<Robot>(camaro);
    bumblebee->move();
    bumblebee->say();
    return 0;
} 
/*
输出
变形金刚是一辆车！
在陆地上移动。
--------------
变成机器人!
在陆地上移动。
说话!
--------------
变成飞机!
在陆地上移动。
在天空飞翔!
*/
```

> 参考：
>
> https://www.nowcoder.com/discuss/632757，
>
> https://leetcode-cn.com/leetbook/read/cpp-interview-highlights/o52f77/

