01 设计模式六大原则
-
开闭原则
对扩展开放,对修改关闭。程序在修改时,不能修改原有的代码,而是要扩展原有的代码,实现热插拔的效果。 -
单一职责原则
一个类应该有且仅有一个引起它变化的原因,否则这个类应该被拆分。 -
里氏替换原则(Liskov Substitution Principle)
子类可以扩展父类的功能,但不能改变父类原有的功能。即子类继承父类时,除添加新的方法完成新增功能外,金陵不要重写父类的方法。 -
依赖倒转原则(Dependence Inversion Principle)
面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。 -
接口隔离原则(Interface Segregation Principle)
每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。 -
迪米特法则/最少知道原则
一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。 -
合成复用原则 (Composite Reuse Principle)
尽量首先使用合成/聚合的方式,而不是使用继承。
02 创建型模式
2.1 单例模式
-
定义
一个类只有一个实例,该类能自行创建,且能对外提供一个访问单例的全局访问点的一种模式。 -
优点
- 可以保证内存中只有一个实例,减少了内存开销。
- 可以避免对资源的多重占用。
- 设置全局访问点,可以优化和共享资源的访问。
-
缺点
- 单例模式一般没有接口,扩展困难。如果要修改就要修改原来的代码,违背了了开闭原则。
- 在并发测试中不利于代码调试。测试中如果单例中的代码没有执行完,不能模拟生成一个新的对象。
- 单例模式的功能和代码通常在一个类中,如果设计不合理,则很容易违背开闭原则。
-
应用场景
- 需要频繁创建的类。使用单例可减少内存压力。
- 需要只生成一个对象的时候。如军团最高长官,校长等。
- 创建实例时占用资源较多,或者实例化耗时比较常。如在堆上实例化本地数据库对象。
- 需要频繁实例化,且创建的对象又频繁被销毁。如多线程的线程池、网络连接池。
- 对于一些控制硬件级别的操作,或单一控制逻辑的操作,多个实例对象会引起混乱。
- 对象需要被共享的场合,如 WEB 中的配置对象、数据库的连接池。
-
两种实现方式
-
懒汉模式
特点是在类加载时没有创建单例,只有当第一次调用实例化的方法时才创建这个单例,因此第一次调用时要进行一系列的初始化工作因此会有一定的延时,初始化完成之后就和饿汉模式用起来一样了。
懒汉模式在多线程下是不安全的,不同的线程可能会创建创建不同的单例对象,需要通过加锁避免这种情况。 -
饿汉模式
特点是类一旦加载就创建一个单例,保证在调用实例化方法之前就已经存在了。
饿汉模式在多线程下是安全的。
-
2.2 观察者模式
-
定义
指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
MVC 模型就是依靠这种模式实现的。 -
优点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系,复合依赖倒置原则。
- 目标与观察者之间建立了一套触发机制。
-
缺点
- 目标与观察者之间的依赖关系并没有完全截除,且可能出现循环引用。
- 当观察者的对象很多时,通知的发布会花费很多时间,影响程序的效率。
-
结构
- 抽象主题(Subject):也叫抽象目标类,它提供一个用于保存观察者对象的聚合类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject):也叫具体目标,它实现抽象目标中的通知方法,当具体主题的内部状态发生变化时,通知所有注册过的观察者对象。
- 抽象观察者(Observer):它是一个抽象类或接口,包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer):实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时自动更新自身的状态。
#include <iostream> #include <string> #include <vector> 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 GameObserver : public Observer { public: GameObserver(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: vector<Observer*> observers; public: string action; virtual void attach(Observer*) = 0; virtual void detach(Observer*) = 0; virtual void notify() = 0; }; // 具体的通知者 class ConcreteSubject : public Subject { void attach(Observer* observer) { observers.push_back(observer); } void detach(Observer* observer) { auto iter = observers.cbegin(); for (; iter != observers.cend() && *iter != observer; ++iter); if (iter != observers.cend()) { observers.erase(iter); } } void notify() { for (auto elem : observers) { elem->update(); } } }; void GameObserver::update() { cout << name << "收到" << sub->action << "的消息了。" << endl; }; void NBAObserver::update() { cout << name << "收到" << sub->action << "的消息了。" << endl; }; int main() { // 创建观察者 Subject* sub = new ConcreteSubject(); // 创建被观察的对象 Observer* obj1 = new GameObserver("张三", sub); Observer* obj2 = new NBAObserver("李四", sub); // 加入观察队列 sub->attach(obj1); sub->attach(obj2); // 触发事件 sub->action = "领福利"; cout << "-- 开始下发" << sub->action << "的通知 --" << endl; sub->notify(); // 触发事件 sub->action = "上报材料"; cout << "-- 开始下发" << sub->action << "的通知 --" << endl; sub->notify(); }
2.3 工厂模式
简单工厂模式
对于不同的产品的创建定义一个工厂类,将产品的类型作为参数传入工厂的创建函数,根据类型分支选择不同的产品构造函数。
typedef enum ProductTypeTag {
TypeA,
TypeB,
} PRODUCY_TYPE;
class Product {
public:
virtual void show() = 0;
};
class ProductA: public Product {
public:
virtual void show() override {
cout << "ProductA::show()" << endl;
}
};
class ProductB: public Product {
public:
virtual void show() override {
cout << "ProductB::show()" << endl;
}
};
class Factory {
public:
Product *createPrduct(PRODUCY_TYPE type) {
switch (type) {
case TypeA:
return new ProductA();
break;
case TypeB:
return new ProductB();
break;
default:
return nullptr;
break;
}
}
};
int main() {
Factory productCreator;
Product *productA = productCreator.createPrduct(TypeA);
Product *productB = productCreator.createPrduct(TypeB);
productA->show();
productB->show();
}
// ProductA::show()
// ProductB::show()
工厂方法模式
简单工厂模式只是简单的创建过程进行封装,工厂方法模式在简单工厂模式的基础上增加对工厂的基类抽象,不同的产品采用不同的工厂创建。
typedef enum ProductTypeTag {
TypeA,
TypeB,
} PRODUCY_TYPE;
class Product {
public:
virtual void show() = 0;
};
class ProductA: public Product {
public:
virtual void show() override {
cout << "ProductA::show()" << endl;
}
};
class ProductB: public Product {
public:
virtual void show() override {
cout << "ProductB::show()" << endl;
}
};
class Factory {
public:
virtual Product *createPrduct() = 0;
};
class FactoryA: public Factory {
public:
virtual Product *createPrduct() override {
return new ProductA();
}
};
class FactoryB: public Factory {
public:
virtual Product *createPrduct() override {
return new ProductB();
}
};
int main() {
Factory *factoryA = new FactoryA();
Product *productA = factoryA->createPrduct();
Factory *factoryB = new FactoryB();
Product *productB = factoryB->createPrduct();
productA->show();
productB->show();
}
// ProductA::show()
// ProductB::show()
抽象工厂模式
工厂方法模式适用于产品种类结构单一的场合,为一类产品提供创建的接口;而抽象工厂方法适用于产品种类结构多的场合,就是当具有多个抽象产品类型时,抽象工厂便可以派上用场。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef enum ProductTypeTag {
TypeA,
TypeB,
} PRODUCY_TYPE;
class ProductA {
public:
virtual void show() = 0;
};
class ProductA1 : public ProductA {
public:
virtual void show() override {
cout << "ProductA1::show()" << endl;
}
};
class ProductA2 : public ProductA {
public:
virtual void show() override {
cout << "ProductA2::show()" << endl;
}
};
class ProductB {
public:
virtual void show() = 0;
};
class ProductB1 : public ProductB {
public:
virtual void show() override {
cout << "ProductB1::show()" << endl;
}
};
class ProductB2 : public ProductB {
public:
virtual void show() override {
cout << "ProductB2::show()" << endl;
}
};
class Factory {
public:
virtual ProductA* createPrductA() = 0;
virtual ProductB* createPrductB() = 0;
};
class Factory1 : public Factory {
public:
ProductA* createPrductA() override {
return new ProductA1();
}
ProductB* createPrductB() override {
return new ProductB1();
}
};
class Factory2 : public Factory {
public:
ProductA* createPrductA() override {
return new ProductA2();
}
ProductB* createPrductB() override {
return new ProductB2();
}
};
int main() {
Factory* factory1 = new Factory1();
ProductA* productA1 = factory1->createPrductA();
ProductB* productB1 = factory1->createPrductB();
productA1->show();
productB1->show();
Factory* factory2 = new Factory2();
ProductA* productA2 = factory2->createPrductA();
ProductB* productB2 = factory2->createPrductB();
productA2->show();
productB2->show();
}
// ProductA1::show()
// ProductB1::show()
// ProductA2::show()
// ProductB2::show()