Skip to content

设计模式(设计和代码实现)

《⼤话设计模式》⼀书中提到 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、单例模式

有两种懒汉和饿汉:

饿汉:饿了就饥不择⻝了,所以在单例类定义的时候就进⾏实例化。

懒汉:顾名思义,不到万不得已就不会去实例化类,也就是在第⼀次⽤到的类实例的时候才会去实例化。

饿汉模式(线程安全):在最开始的时候静态对象就已经创建完成,设计⽅法是类中包含⼀个静态成员指针,该指针指向该类的⼀个对象,提供⼀个公有的静态成员⽅法,返回该对象指针,为了使得对象唯⼀,构造函数设为私有。

cpp
#include <iostream>
#include <algorithm>
usingnamespacestd;
classSingleInstance {
public:
static SingleInstance* GetInstance() {
static SingleInstance ins;
return &ins;
}
~SingleInstance(){};
private:

//涉及到创建对象的函数都设置为privateSingleInstance() { std::cout<<"SingleInstance() 饿汉"<<std::endl;

cpp
}
SingleInstance(const SingleInstance& other) {};
SingleInstance& operator=(const SingleInstance& other) {return
*this;}
};
intmain(){

//因为不能创建对象所以通过静态成员函数的⽅法返回静态成员变量

cpp
SingleInstance* ins = SingleInstance::GetInstance();
return0;
}

//输出 SingleInstance() 饿汉

懒汉模式(线程安全需要加锁):尽可能的晚的创建这个对象的实例,即在单例类第⼀次被引⽤的时候就将⾃⼰初始化,C++很多地⽅都有类型的思想,⽐如写时拷⻉,晚绑定等。

cpp
#include <pthread.h>
#include <iostream>
#include <algorithm>
usingnamespacestd;
classSingleInstance {
public:
static SingleInstance* GetInstance() {
if (ins == nullptr) {
pthread_mutex_lock(&mutex);
if (ins == nullptr) {
ins = new SingleInstance();
}
pthread_mutex_unlock(&mutex);
}
return ins;
}
~SingleInstance(){};

//互斥锁

cpp
static pthread_mutex_t mutex;
private:

//涉及到创建对象的函数都设置为privateSingleInstance() { std::cout<<"SingleInstance() 懒汉"<<std::endl;

cpp
}
SingleInstance(const SingleInstance& other) {};
SingleInstance& operator=(const SingleInstance& other) {  return
*this; }

//静态成员

cpp
static SingleInstance* ins;
};

//懒汉式静态变量需要定义

cpp
SingleInstance* SingleInstance::ins = nullptr;
pthread_mutex_t SingleInstance::mutex;
intmain(){

//因为不能创建对象所以通过静态成员函数的⽅法返回静态成员变量

cpp
SingleInstance* ins = SingleInstance::GetInstance();
delete ins;
return0;
}

//输出 SingleInstance() 懒汉单例模式的适⽤场景

(1)系统只需要⼀个实例对象,或者考虑到资源消耗的太⼤⽽只允许创建⼀个对象。

(2)客户调⽤类的单个实例只允许使⽤⼀个公共访问点,除了该访问点之外不允许通过其它

⽅式访问该实例(就是共有的静态⽅法)。

4、⼯⼚模式

简单⼯⼚模式:

就是建⽴⼀个⼯⼚类,对实现了同⼀接⼝的⼀些类进⾏实例的创建。简单⼯⼚模式的实质是由⼀个⼯⼚类根据传⼊的参数,动态决定应该创建哪⼀个产品类(这些产品类继承⾃⼀个⽗类或接⼝)的实例。

cpp
#include <iostream>
#include <pthread.h>
usingnamespacestd;

//产品类(抽象类,不能实例化)

cpp
classProduct{
public:
Product(){};

virtualvoid show()=0; //纯虚函数

cpp
};
classproductA : public Product{
public:
productA(){};
void show(){ std::cout << "product A create!" << std::endl; };
~productA(){};
};
classproductB : public Product{
public:
productB(){};
void show(){ std::cout << "product B create!" << std::endl; };
~productB(){};
};

classsimpleFactory{ // ⼯⼚类

cpp
public:
simpleFactory(){};
Product* product(const string str){
if (str == "productA")
returnnew productA();
if (str == "productB")
returnnew productB();
return NULL;
};
};
intmain(){

simpleFactory obj; // 创建⼯⼚Product* pro; // 创建产品

cpp
pro = obj.product("productA");
pro->show(); // product A create!
delete pro;
pro = obj.product("productB");
pro->show(); // product B create!
delete pro;
return0;
}

⼯⼚模式⽬的就是代码解耦,如果我们不采⽤⼯⼚模式,如果要创建产品 A、B,通常做法采⽤⽤ switch...case语句,那么想⼀想后期添加更多的产品进来,我们不是要添加更多的switch...case 吗?这样就很麻烦,⽽且也不符合设计模式中的开放封闭原则。

为了进⼀步解耦,在简单⼯⼚的基础上发展出了抽象⼯⼚模式,即连⼯⼚都抽象出来,实现了进⼀步代码解耦。

代码如下:

cpp
#include <iostream>
#include <pthread.h>
usingnamespacestd;

//产品类(抽象类,不能实例化)

cpp
classProduct{
public:
Product(){}

virtualvoid show()=0; //纯虚函数

cpp
};

classFactory{//抽象类

cpp
public:

virtual Product* CreateProduct()=0;//纯虚函数

cpp
};

//产品A

cpp
classProductA:public Product{
public:
ProductA(){}
void show(){ std::cout<<"product A create!"<<std::endl; };
};

//产品B

cpp
classProductB:public Product{
public:
ProductB(){}
void show(){ std::cout<<"product B create!"<<std::endl; };
};

//⼯⼚类A,只⽣产A产品

cpp
classFactorA: public Factory{
public:
Product* CreateProduct(){
Product* product_ = nullptr;
product_ = new ProductA();
return product_;
}
};

//⼯⼚类B,只⽣产B产品

cpp
classFactorB: public Factory{
public:
Product* CreateProduct(){
Product* product_ = nullptr;
product_ = new ProductB();
return product_;
}
};
intmain(){
Product* product_ = nullptr;
auto MyFactoryA = new FactorA();

product_ = MyFactoryA->CreateProduct();// 调⽤产品A的⼯⼚来⽣产A产品

cpp
product_->show();
delete product_;
auto MyFactoryB=new FactorB();

product_ = MyFactoryB->CreateProduct();// 调⽤产品B的⼯⼚来⽣产B产品

cpp
product_->show();
delete product_;
return0;
}

//输出

cpp
//product A create! product B create!

5、观察者模式

观察者模式:定义⼀种⼀(被观察类)对多(观察类)的关系,让多个观察对象同时监听⼀个被观察对象,被观察对象状态发⽣变化时,会通知所有的观察对象,使他们能够更新⾃⼰的状态。

观察者模式中存在两种⻆⾊:

观察者:内部包含被观察者对象,当被观察者对象的状态发⽣变化时,更新⾃⼰的状态。(接收通知更新状态)

被观察者:内部包含了所有观察者对象,当状态发⽣变化时通知所有的观察者更新⾃⼰的状态。(发送通知)应⽤场景:

当⼀个对象的改变需要同时改变其他对象,且不知道具体有多少对象有待改变时,应该考虑使⽤观察者模式;

⼀个抽象模型有两个⽅⾯,其中⼀⽅⾯依赖于另⼀⽅⾯,这时可以⽤观察者模式将这两者封装在独⽴的对象中使它们各⾃独⽴地改变和复⽤。

实现⽅式:

cpp
#include <iostream>
#include <string>
#include <list>
usingnamespacestd;
classSubject;

//观察者基类(内部实例化了被观察者的对象sub)

cpp
classObserver {
protected:
string name;
Subject *sub;
public:
Observer(string name, Subject *sub) {
this->name = name;
this->sub = sub;
}
virtualvoid update() = 0;
};
classStockObserver : public Observer {
public:
StockObserver(string name, Subject *sub) : Observer(name, sub){}
void update();
};
classNBAObserver : public Observer {
public:
NBAObserver(string name, Subject *sub) : Observer(name, sub){}
void update();
};

//被观察者基类(内部存放了所有的观察者对象,以便状态发⽣变化时,给观察者发通知)

cpp
classSubject {
protected:
std::list<Observer *> observers;
public:

string action; //被观察者对象的状态

cpp
virtualvoid attach(Observer *) = 0;
virtualvoid detach(Observer *) = 0;
virtualvoid notify() = 0;
};
classSecretary : 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;
}
}
};
voidStockObserver::update() {

cout << name << " 收到消息:" << sub->action << endl;if (sub->action == "⽼板来了!") {cout << "我⻢上关闭股票,装做很认真⼯作的样⼦!" << endl;

cpp
}
}
voidNBAObserver::update() {

cout << name << " 收到消息:" << sub->action << endl;if (sub->action == "⽼板来了!") {cout << "我⻢上关闭 NBA,装做很认真⼯作的样⼦!" << endl;

cpp
}
}
intmain()
{
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 = "去吃饭了!";

cpp
BOSS->notify();
cout << endl;

BOSS->action = "⽼板来了!";

cpp
BOSS->notify();
return0;
}

//输出

cpp
//product A create! product B create!

6、装饰器模式

装饰器模式(Decorator Pattern)允许向⼀个现有的对象添加新的功能,同时⼜不改变其结构。

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

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

cpp
#include <iostream>
#include <list>
#include <memory>
usingnamespacestd;

//抽象构件类 Transform (变形⾦刚)

cpp
classTransform{
public:
virtualvoid move() = 0;
};

//具体构件类Car

cpp
classCar : public Transform{
public:
Car(){

std::cout << "变形⾦刚是⼀辆⻋!" << endl;

cpp
}
void move(){

std::cout << "在陆地上移动。" << endl;

cpp
}
};

//抽象装饰类

cpp
classChanger : public Transform{
public:
Changer(shared_ptr<Transform> transform){
this->transform = transform;
}
void move(){
transform->move();
}
private:
shared_ptr<Transform> transform;
};

//具体装饰类Robot

cpp
classRobot : public Changer{
public:
Robot(shared_ptr<Transform> transform) : Changer(transform){

std::cout << "变成机器⼈!" << std::endl;

cpp
}
void say(){

std::cout << "说话!" << std::endl;

cpp
}
};

//具体装饰类AirPlane

cpp
classAirplane : public Changer{
public:
Airplane(shared_ptr<Transform> transform) : Changer(transform){

std::cout << "变成⻜机!" << std::endl;

cpp
}
void say(){

std::cout << "在天空⻜翔!" << std::endl;

cpp
}
};
intmain(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();
return0;
}
/*

输出变形⾦刚是⼀辆⻋!

在陆地上移动。

cpp
--------------

变成机器⼈!

在陆地上移动。

说话!

cpp
--------------

变成⻜机!

在陆地上移动。

在天空⻜翔!

cpp
*/

参考:

https://www.nowcoder.com/discuss/632757,https://leetcode-cn.com/leetbook/read/cpp-interview-highlights/o52f77/以上部分知识整理来源于⽹络,侵权必删。

哈喽,我是⼩贺哥,就爱分享编程知识,如果觉得⽂章对你有帮助,别忘记关注我哦!

设计模式(设计和代码实现) 图 151

加餐-图解 STL 源码

用心记录,持续成长