1. 设计原则
(1)设计模式是在软件开发中,经过验证的、在特定场景的解决方案。另⼀种说法是扩展隔离变化点,抽象稳定点。设计原则如下:
- 单⼀职责原则:就⼀个类而言,应该仅有⼀个引起它变化的原因。
- 开放封闭原则:对程序的改动可以通过增加代码来完成,但是不能改动现有的代码。
- 里氏代换原则:如果⼀个实体适用⼀个基类,那么⼀定适用于其派生类。
- 依赖倒置原则:针对接口编程,不要针对实现编程。
- 迪米特原则:如果⼀个类需要调用另⼀个类的某个方法的话,可以通过第三个类转发这个调用。
- 接口隔离原则:每个接口中不应该存在派⽣类用不到却必须实现的方法,否则就要将接口拆分。
2. 常用的设计模式
2.1 单例模式
(1)保证⼀个类仅有⼀个实例,并提供⼀个访问它的方法。有饿汉模式和懒汉模式两种,饿汉模式是该类定义的时候进行实例化,且是线程安全的。
- 懒汉模式:
class Singleton
{
private:Singleton() {}~Singleton() {}
public:static Singleton& getInstance() {static Singleton instance;return instance;}
}
- 饿汉模式:
class Singleton
{
private:static Singleton instance;Singleton() {}~Singleton() {}
public:static Singleton& getInstance() {return instance;}
};Singleton Singleton::instance;
2.2 简单工厂模式
(1)主要用于创建对象。用一个工厂来根据输入的条件产生不同的类,然后依据不同类的虚函数得到不同的结果。创建对象之间无依赖。
- 产品基类定义纯虚函数,其派生类实现该虚函数。工厂类定义返回产品接口的函数,通过判断传入的参数确定返回产品类型。简单工厂模式:
#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;
}
2.3 模板方法
(1)定义⼀个操作中的算法框架,而将⼀些步骤延迟到子类中。该方法使得子类可以不改变⼀个算法的结构即可重定义该算法的某些特定步骤。
- 基类实现总处理步骤顺序的函数,而每个步骤定义为虚函数。派生类实现所要改变某步骤的虚函数即可。步骤流程如下:
#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;
}
2.4 责任链模式
(1)使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间存在耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有个对象处理它为止。
- 基类有个指向自己的指针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;
}
2.5 装饰器模式
(1)动态地给对象增加额外的功能。就增加功能而言,该模式比生成子类更为灵活。(与责任链最大不同在于是否有顺序关系)。
- 基类有⼀个指向自己的指针变量,同时有⼀个原始功能函数,被定义为虚函数。派生类实现该虚函数,并通过基类指针调用基类的功能函数。奖⾦类别增添流程如下:
#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;
}