五、设计模式
设计模式是在软件开发中,经过验证的、在特定场景的解决⽅案。另⼀种说法是扩展隔离变化点,抽象稳定点。
5.1 设计原则
1. 单⼀职责原则:就⼀个类⽽⾔,应该仅有⼀个引起它变化的原因。
2. 开放封闭原则:对程序的改动可以通过增加代码来完成,但是不能改动现有的代码
3. ⾥⽒代换原则:如果⼀个实体适⽤⼀个基类,那么⼀定适⽤于其派⽣类
4. 依赖倒置原则:针对接⼝编程,不要针对实现编程
5. 迪⽶特原则:如果⼀个类需要调⽤另⼀个类的某个⽅法的话,可以通过第三个类转发这个调⽤
6. 接⼝隔离原则:每个接⼝中不应该存在派⽣类⽤不到却必须实现的⽅法,否则就要将接⼝拆分
5.2 常⽤设计模式
单例模式
保证⼀个类仅有⼀个实例,并提供⼀个访问它的⽅法。有饿汉模式和懒汉模式两种,饿汉模式是该类定义的时候进⾏实例化,且是线程安全的。
饿汉式
class Singleton
{public:static Singleton *getInstance(){return instance;}private:// Singleton() = default;Singleton() {}Singleton(const Singleton &instance) = default;Singleton &operator=(const Singleton &instance) = default;static Singleton *instance;
};Singleton *Singleton::instance = new Singleton();
懒汉式
#include <mutex>class Singleton
{public:static Singleton *getInstance(){if (instance == nullptr){mtx.lock();if (instance == nullptr){instance = new Singleton();}mtx.unlock();}return instance;}private:Singleton() = default;Singleton(const Singleton &instance) = default;Singleton &operator=(const Singleton &instance) = default;static Singleton *instance;static mutex mtx;
};mutex Singleton::mtx;
Singleton *Singleton ::instance = nullptr;
简单⼯⼚模式
主要⽤于创建对象。⽤⼀个⼯⼚来根据输⼊的条件产⽣不同的类,然后依据不同类的虚函数得到不同的结果。创建对象之间⽆依赖。产品基类定义纯虚函数,其派⽣类实现该虚函数。⼯⼚类定义返回产品接⼝的函数,通过判断传⼊的参数确定返回产品类型。
#include <bits/stdc++.h>
using namespace std;
class IProduct {
public:
virtual void show() = 0;virtual ~Product(){};
};
class ProductA : public IProduct {
public:
void show() {
cout << "ProductA.show()" << endl;
}
~ProductA(){};
};
class ProductB : public IProduct {
public:
void show() {
cout << "ProductB.show()" << endl;
}
~ProductB(){};
};
class SimpleFactory {
public:
IProduct* product(const string str) {
if (str == "productA") {
return new ProductA();
}
else if (str == "productB") {
return new ProductB();
}
return nullptr;
}
};
int main() {
SimpleFactory fac;
IProduct* pro;
pro = fac.product("productA");
pro->show();
delete pro;
pro = fac.product("productB");
pro->show();
delete pro;
return 0;
}
模板⽅法
定义⼀个操作中的算法框架,⽽将⼀些步骤延迟到⼦类中。该⽅法使得⼦类可以不改变⼀个算法的结构即可重定义该算法的某些特定步骤。基类实现总处理步骤顺序的函数,⽽每个步骤定义为虚函数。派⽣类实现所要改变某步骤的虚函数即可。
#include <bits/stdc++.h>
using namespace std;
class Show {
public:
void show() { // 固定流程封装到这⾥
show0();
show1();
show2();
show3();
}
protected:
// ⼦流程 允许⼦类访问,防⽌客户调⽤
virtual void show0() {
cout << "show0" << endl;
}
virtual void show1() {
cout << "show1" << endl;
}
virtual void show2() {
cout << "show2" << endl;
}
virtual void show3() {
cout << "show3" << endl;
}
};
class ShowEx: public Show {
protected:
virtual void show1() {
cout << "show1 update" << endl;
}
virtual void show2() {
cout << "show2 update" << endl;
}
};
int main() {
Show* zs = new ShowEx;
zs->show();return 0;
}
责任链模式
使多个对象都有机会处理请求,从⽽避免请求的发送者和接收者之间存在耦合关系。将这些对象连成⼀条链,并沿着这条链传递请求,直到有个对象处理它为⽌。基类有个指向⾃⼰的指针next,还有两个函数,分别是定义为纯虚函数的处理函数和设置下⼀个对象的函数。派⽣类实现虚处理函数(包含⾃⼰的处理逻辑、传递给下⼀个对象操作、⽆法处理对应的操作等)
#include <bits/stdc++.h>
using namespace std;
class IHandler {
protected:
IHandler *next;
public:
void setNextHandler(IHandler* n) { next = n; }
virtual bool handleRequest(string ctx) = 0;
};
class HandleByMainProgram: public IHandler {
public:
virtual bool handleRequest(string ctx) {
if (ctx == "1") {
cout << "HandleByMainProgram" << endl;
}
else if (next){
next->handleRequest(ctx);
}
else {
cout << "NO" << endl;
}
}
};
class HandleByProjMgr: public IHandler {
public:
virtual bool handleRequest(string ctx) {
if (ctx == "2") {
cout << "HandleByProjMgr" << endl;
}
else if (next){
next->handleRequest(ctx);
}
else {
cout << "NO" << endl;
}
}
};
class HandleByBoss: public IHandler {
public:
virtual bool handleRequest(string ctx) {
if (ctx == "3") {
cout << "HandleByBoss" << endl;
}
else if (next){
next->handleRequest(ctx);
}
else {
cout << "NO" << endl;
}
}
};
int main() {
IHandler *h1 = new HandleByMainProgram();
IHandler *h2 = new HandleByProjMgr();
IHandler *h3 = new HandleByBoss();
h1->setNextHandler(h2);
h2->setNextHandler(h3);
h1->handleRequest("3");return 0;
}
装饰器模式
动态地给对象增加额外的功能。就增加功能⽽⾔,该模式⽐⽣成⼦类更为灵活。(与责任链最⼤不同在于是否有顺序关系)。 基类有⼀个指向⾃⼰的指针变量,同时有⼀个原始功能函数,被定义为虚函数。派⽣类实现该虚函数,并通过基类指针调⽤基类的功能函数。
#include <bits/stdc++.h>
using namespace std;
class CalcBonus {
public:
CalcBonus(CalcBonus *c = nullptr): cc(c) {}
virtual double calc(Context &ctx) {
return 0.0;
}
protected:
CalcBonus *cc;
};
class CalcMonthBonus: public CalcBonus {
public:
CalcMonthBonus(CalcBonus *c): CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double mbonus = 0.0;
return mbonus + cc->calc(ctx);
}
};
class CalcSumBonus: public CalcBonus {
public:
CalcSumBonus(CalcBonus *c): CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double sbonus = 0.0;
return sbonus + cc->calc(ctx);
}
};
class CalcGroupBonus: public CalcBonus {
public:
CalcGroupBonus(CalcBonus *c): CalcBonus(c) {}
virtual double Calc(Context &ctx) {
double gbonus = 0.0;
return gbonus + cc->calc(ctx);
}
};
int main() {
// 普通员⼯
Context ctx1;
CalcBonus *base = new CalcBonus();
CalcBonus *cb1 = new CalcMonthBonus(base);
CalcBonus *cb2 = new CalcSumBonus(cb1);
cb2->calc(ctx1);
// 部⻔经理
Context ctx2;
CalcBonus *cb3 = new CalcGroupBonus(cb2);
cb3->calc(ctx2);return 0;
}
观察者设计模式,如何实现
1. 观察者设计模式的定义
指 多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到
通知并被自动更新 。这种模式有时又称作发布 - 订阅模式、模型 - 视图模式,它是对象行为型模式。
2. 优点
( 1 ) 降低了目标与观察者之间的耦合关系 ,两者之间是抽象耦合关系。符合依赖倒置原则。
( 2 ) 目标与观察者之间建立了一套触发机制。
3. 缺点
( 1 )目标与观察者之间的依赖关系并没有完全解除,而且有可能出 现循环引用。
( 2 ) 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
4. 观察者设计模式的结构与实现
观察者模式的主要角色如下:
( 1 ) 抽象主题 ( Subject )角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和
增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
( 2 ) 具体主题 ( Concrete Subject )角色:也叫具体目标类,它实现抽象目标中的通知方法,当
具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
( 3 ) 抽象观察者 ( Observer )角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方
法,当接到具体主题的更改通知时被调用。
( 4 ) 具体观察者 ( Concrete Observer )角色:实现抽象观察者中定义的抽象方法,以便在得到
目标的更改通知时更新自身的状态。
可以举个博客订阅的例子,当博主发表新文章的时候,即博主状态发生了改变,那些订阅的读者就会收 到通知,然后进行相应的动作,比如去看文章,或者收藏起来。博主与读者之间存在种一对多的依赖关系。
#include <iostream>
#include <vector>
#include <list>
#include <memory>
#include <algorithm>
using namespace std;//观察者 --用户
class Observer
{
public:Observer() {}virtual ~Observer() {}virtual void Update() {}
};//博客 --主题
class Blog
{
public:Blog() {}virtual ~Blog() {}void Attach(Observer *observer){m_observers.push_back(observer);}void Remove(Observer *observer){m_observers.remove(observer);}void Notify(){list<Observer *>::iterator iter = m_observers.begin();for (; iter != m_observers.end(); iter++){(*iter)->Update();}}virtual void SetStatus(string s){m_status = s;} //设置状态virtual string GetStatus(){return m_status;} //获得状态private:list<Observer *> m_observers; //观察者链表protected:string m_status; //状态。
};//具体 主题
class BlogCSDN : public Blog
{
private:string m_name;public:BlogCSDN(string name) : m_name(name) {}~BlogCSDN() {}virtual void setStatus(string s){m_status = "CSDN 通知:" + m_name + s; //具体设置状态信息}string GetStatus(){return m_status;}
};//具体观察者。
class ObserverBlog : public Observer
{private:string m_name;Blog *m_blog;public:ObserverBlog(string name, Blog *blog) : m_name(name), m_blog(blog) {}~ObserverBlog() {}void Update(){string status = m_blog->GetStatus();cout << m_name << "--------------------" << status << endl;}
};//测试案例。
int main()
{Blog *blog = new BlogCSDN("wuzhekai1985");Observer *observer1 = new ObserverBlog("tutupig", blog);blog->Attach(observer1);blog->SetStatus("Publishing Design Pattern C++Implementation (15) - Observer Pattern");blog->Notify();delete blog;delete observer1;system("pause");return 0;
}