这篇文章会简单粗暴地讲解一下常用设计模式,算是一个汇总,不会作详细地讲解
系统设计从设计原则开始,在过程中会自然而然发现需要加入模式的地方。所有的原则都不是必须遵守的,要考虑全局进行舍取,常常要折中。
所有的设计模式都是一种思想,即使在某种场合下没有办法实现常规的写法,但是用到它们的思想就可以了。尽可能保持设计的简单,只有真正需要模式时才使用,复杂度一般与灵活性正相关。
使用设计模式的目的:在不改变设计好的运行框架的前提下,需增加功能是只需要额外添加一个类,然后就可以在系统运行时增加功能
能够被适配的目标类一定有着可重写的接口,能够被适配的目标函数一定是虚函数
class Adapter : public absClassA { absClassB* realInstance; //被适配 def func() override { //Todo:调用realInstance的一些方法 } };
尽量减少一个类中对于其它类的引用,以减少调用一个功能需要.出来的次数
这个模式中使用继承是为了能够做到类型匹配,因为一个对象在被装饰之后还必须是原来的那个对象类型。不能因为装饰而改变自己的类型。一个化了妆的人还是一个人
能够被装饰的类一定有着可重写的接口,能够被装饰的函数一定是虚函数
class Decorator : absClass { absClass* realInstance; //被装饰者 def func() override { realInstance->func(); //Todo:do more something } };
对扩展开放,对修改关闭
代理(proxy):代表特定实例
能够被代理的类一定有着可重写的接口,能够被代理化的函数一定是虚函数
创建代理通常会使用工厂方法
class Proxy : absClass { absClass* realInstance; void func() override { #if 0 //保护代理 //通过一些条件控制对realInstance的访问 if(满足条件) realInstance->func(); #elif 0 //虚拟代理 if(realInstance != NULL) realInstance->func(); else //开启异步线程创建absClass实例 //或 执行默认操作 #else //远程代理 realInstance->func(); //func通过网络和远程实例通信 #endif } };
装饰者模式的目的是为对象加上行为,而代理模式的目的是控制对对象的访问
观察感兴趣的事物 或者 事情
class Subject //可以被包含 { absClass*[] observers; //核心数据结构 }
对象之间保持松耦合
class xxx:absClass { absClass*[] a; }
class Iterator { def hasNext() = 0; def next() = 0; }
class xxx:Iterator { Iterator*[] it; def hasNext() override {...} def next() override {...} }
每个类保持单一的责任
多用接口
class xxx { absClassA* a; absClassB* b; absClassC* c; ... }
基于有限状态机;允许对象在内部状态改变时改变它的行为,对象好像在运行过程中修改了它的类定义
class State { def Enter() = 0; def Exit() = 0; //其它纯虚函数 def DoSomethingA() = 0; ... } class StateMachine { State* curState; //核心数据结构 def changeState(State* newState) //核心函数 { curState->Exit(); curState = newState; curState->Enter(); } //其他纯虚函数的实现 def DoSomethingA() { curState->DoSomethingA(); } ... }
策略模式和状态模式本质上是相同的,只是状态模式在执行逻辑时,状态可以自动发生改变
降低了状态的数量
一个对象拥有两个状态机,分别负责m种A类状态、n种B类状态,实现A类状态和B类状态的组合
实现了代码重用
用继承来实现:子类不处理的输入交给来父类处理
用栈来实现:每一个元素都是它下一个元素的子状态,接收到输入时,从栈顶开始向下查找可以处理输入的那个状态来处理该输入
实现了状态回退功能
状态机使用一个栈来记录历史状态,栈顶代表当前状态
C++11标准之后的最佳选择
全局唯一、有全局访问点,但延迟构建不是必须的
class Singleton { public: static Singleton* getInstance() { static Singleton s; return &s; } }
一般类的构造和析构函数可以不做任何事情,定义额外的startUp和shutDown函数
将发出请求的对象和执行请求的对象进行解耦
命令模式的一个强大功能就是撤销
class Command { void execute() = 0; void undo() = 0; } class Remote { map<int, Command*> commands; //核心数据结构 statck<Command*> historyCommands; }
class Template { def mainProcess() { funcA(); funcB(); if(funcC()) funcD(); ... } def funcA() = 0; def funcB() = 0; def funcC() = 0; def funcD() = 0; }
低层组件不可以调用高层组件,但是高层组件可以调用低层组件
抽象类的具体类比较多、需要分类或创建过程比较复杂时,可以用工厂模式将创建它们的函数封装起来
class AbsProduct { } class Product1 : AbsProduct { } class Product2 : AbsProduct { } AbsProduct* create(string name) { if(...) return new Product1(); else if(...) return new Product2(); ... }
class AbsProduct { } class Product1 : AbsProduct { } class Product2 : AbsProduct { } ... class AbsFactory { public: virtual AbsProduct createProduct() = 0; } class Factory1 : AbsFactory { public: override AbsProduct createProduct() { ... return new Product1(); } } class Factory2 : AbsFactory { public: override AbsProduct createProduct() { ... return new Product2(); } } ...
class AbsProductA { } class ProductA1 : AbsProductA { } class ProductA2 : AbsProductA { } ... class AbsProductB { } class ProductB1 : AbsProductB { } class ProductB2 : AbsProductB { } ... class AbsFactory { public: virtual AbsProductA createProductA() = 0; virtual AbsProductB createProductB() = 0; } class Factory1 : AbsFactory { public: override AbsProductA createProductA() { ... return new ProductA1(); } override AbsProductB createProductB() { ... return new ProductB1(); } } class Factory2 : AbsFactory { public: override AbsProductA createProductA() { ... return new ProductA2(); } override AbsProductB createProductB() { ... return new ProductB2(); } } ...
依赖倒置原则:要依赖抽象类,不要依赖具体类
复合模式:结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题
MVC的本质就是将数据、显示、逻辑分开,一切以实现这个目标为目的的设计都可以说是MVC,以下是其中一种设计:
view和controller之间的关系可以是1对1、1对n、n对1