总览
设计模式(Design pattern)是被用来在特定场景下解决一般设计问题类和相互通信的对象的描述。
如果说现在的高端大气上档次的开源大作是上乘武林绝学,那么设计模式就应该尊为顶尖内功心法。历数那些武功高强之人,无一不是集内外功法之大成者。
目前来看,技术的发展演进之快使得很多人都跟不上。当初的你还在SpringMvc的时候,现在早已经微服务了。当我们还在向微服务化改造的时候,别人已经开始玩服务网格了。所以说,我们现在使用的技术很可能不久就会淘汰,塞班与安卓就是一个很好的例子。那么,当武林绝学沦为三脚猫功夫,我们将何去何从?
电影《温凉珠》里,小长峰和他爹在院子里练气(内功),小长峰向他爹吐槽说练气没用,出去打架一次也没打赢过。他爹回应道:“练气的人命大不容易死”。
是的,塞班虽说已经过去,但是在塞班开发中积累的设计理念却不会过时。so,扯了这么多没用的,总结就一句话设计模式将是我们在技术生涯中经久不衰的秘诀。
在总结设计模式之前,我们需要先来了解一下设计模式所遵守的设计原则。首先要说明,这些原则不需要全部都遵守,恰恰相反全部遵守的系统一定不是最优的系统。时间证明,最优的系统一定是满足以下原则的部分原则,在以下原则中进行权衡与取舍,才能设计出高质量的工程。
设计原则
- 开闭原则(Open Close Principle)
- 规定:一个软件实体如类、模块和函数应该对拓展开放,对修改关闭。
- 含义:用抽象实现框架,用实现拓展细节,提高系统复用及维护性
- 单一职责原则(Single Responsibility Principle)
- 规定:不要存在多于一个导致类变更的原因
- 含义:一个接口只负责一项职责,提高系统可读性维护性
- 里氏代换原则(Liskov Substitution Principle)
- 规定:所有引用父类的地方必须能透明地使用其子类的对象
- 含义:约束继承关系,让子类可以拓展父类功能但不能改变父类原有功能,也是开闭原则的体现
- 依赖倒转原则(Dependence Inversion Principle)
- 规定:高层模块不应该依赖底层模块,二者都应该依赖其抽象
- 含义:抽象的接口不应依赖具体的实现,但实现必须依赖抽象的接口,要面向接口编程。
- 接口隔离原则(Interface Segregation Principle)
- 规定:用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口
- 含义:尽量细化接口,不要使接口庞大臃肿,但这里需要权衡,适度即可
- 迪米特法则,又称最少知道原则(Demeter Principle)
- 规定:一个对象应该对其他的对象保持最少了解
- 含义:降低系统的耦合程度
- 合成复用原则(Composite Reuse Principle)
- 规定:尽量使用对象组合,而不是继承关系达到软件复用
- 含义:通过组合让系统更加灵活,降低耦合度
基于这些原则,我们在来总结下GOF经典的设计模式。
设计模式
首先设计模式可以分为以下三种类型
- 创建型模式
- 结构型模式
- 行为型模式
模式之间的关系,可以看参考以下这张图。
下面我们来具体总结一下。
创建型模式
- 简单工厂模式(Factory Pattern)
- 概述:由工厂决定创建出哪一种产品的实例
- 优点:降低系统耦合
- 缺点:违反开闭原则
- 使用场景:工厂负责创建的对象较少时
- 抽象工厂模式(Abstract Factory Pattern)
- 概述:创建一系列相关或相互依赖的接口
- 优点:可以将产品族统一到一起创建
- 缺点:难以增加新的产品等级
- 使用场景:创建一个或多个产品族工厂
- 单例模式(Singleton Pattern)
- 概述:保证类仅有一个实例,并提供一个全局访问点
- 优点:节约资源减少开销,严格控制访问
- 缺点:有线程安全问题
- 使用场景:需要全局唯一实例对象创建时
- 建造者模式(Builder Pattern)
- 概述:将复杂对象的创建与表示分离
- 优点:解耦创建与使用过程
- 缺点:产生多于建造类,内部改变时需要同时改变建造者,违反开闭原则
- 使用场景:对象内部结构复杂,需要将创建过程分解时
- 原型模式(Prototype Pattern)
- 概述:通过拷贝原型创建新的对象
- 优点:性能好,创建过程易实现
- 缺点:需要注意深拷贝/浅拷贝问题
- 使用场景:对象初始化成本较高或大量创建时
结构型模式
- 适配器模式(Adapter Pattern)
- 概述:将原本接口不兼容的类可以一起工作
- 优点:符合开闭原则,提高了系统复用性
- 缺点:降低了系统可读性
- 使用场景:项目维护中,新需求与老代码复用时使用
- 桥接模式(Bridge Pattern)
- 概述:将抽象与它的实现分离,使他们都可以独立变化
- 优点:符合开闭原则,拓展性好
- 缺点:增加了系统复杂性
- 使用场景:一个类存在两个或多个变化维度,且各维度都需要进行拓展
- 组合模式(Composite Pattern)
- 概述:将对象组成树形结构以表示“部分-整体”的层次结构
- 优点:方便对总体进行控制
- 缺点:需要注意深拷贝/浅拷贝问题
- 使用场景:需要抽象树形结构时
- 装饰器模式(Decorator Pattern)
- 概述:动态的给某一对象添加额外的职责
- 优点:符合开闭原则,使用较为灵活
- 缺点:难排错及debug
- 使用场景:动态地给一个对象添加功能时
- 外观模式(Facade Pattern)
- 概述:为子系统提供统一的界面,从而使得子系统加统一的使用
- 优点:符合迪米特原则
- 缺点:不符合开闭原则
- 使用场景:接口封装
- 享元模式(Flyweight Pattern)
- 概述:利用共享技术有效的支持大量细粒度的对象
- 优点:元数据复用,减少内存开销
- 缺点:注意线程安全
- 使用场景:系统中存在大量相同的基础对象时
- 代理模式(Proxy Pattern)
- 概述:为其他对象提供一种代理以控制这个对象的访问
- 优点:保护和增强了代理对象
- 缺点:降低了系统响应速度,增加了系统复杂度
- 使用场景:需要增强目标对象时
行为型模式
- 责任链模式(Chain of Responsibility Pattern)
- 概述:将处理对象连接起来,并将请求沿该链传递,直至被解决
- 优点:使处理构成更灵活
- 缺点:增加系统复杂度
- 使用场景:某一请求需要对个对象进行协作处理时
- 命令模式(Command Pattern)
- 概述:将请求封装为一个对象,从而使你可用不同的请求对客户进行参数化
- 优点:符合开闭原则,易拓展新命令
- 缺点:命令较多时增加系统复杂度
- 使用场景:请求与执行者需要解耦时
- 解释器模式(Interpreter Pattern)
- 概述:定义一个语言,定义它的文法的一种表示,定义一个解释器来解释语言中的句子
- 优点:容易改变解释和拓展
- 缺点:语法规则复杂而难以维护
- 使用场景:用于解决高频的特定问题
- 迭代器模式(Iterator Pattern)
- 概述:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需暴露该对象的内部表示
- 优点:解耦对象行为与遍历
- 缺点:需要提供每一个聚合对象的具体遍历器
- 使用场景:访问一个聚合对象,而不想暴露其内部表示
- 中介者模式(Mediator Pattern)
- 概述:用一个中介者对象来封装一系列的对象交互
- 优点:将协作抽象化,集中控制
- 缺点:增加系统的理解成本
- 使用场景:各个对象之间有公共的交互行为时(聊天室)
- 备忘录模式(Memento Pattern)
- 概述:在不破坏封装性的前提下,捕获一个对象的状态进行保存
- 优点:利于状态回滚
- 缺点:浪费资源
- 使用场景:编辑撤销,数据备份恢复查询
- 观察者模式(Observer Pattern)
- 概述:定义一种一对多的依赖关系,使得每当一个状态发生改版时,其相关依赖对象皆得到通知并被自动更新
- 优点:广播通信,符合开闭原则
- 缺点:需要注意循环调用
- 使用场景:消息发布订阅
- 状态模式(State Pattern)
- 概述:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类
- 优点:减少条件语句的使用,让状态改变显示化
- 缺点:增加了系统复杂度
- 使用场景:对象运行中需要根据状态变化而不断改变其行为时
- 策略模式(Strategy Pattern)
- 概述:定义一系列的算法,把他们封装起来,并且使他们可以相互替换,使得算法独立于使用它的客户而变化
- 优点:符合开闭原则,易增新算法,减少了条件语句使用
- 缺点:客户端需要了解不同的策略
- 使用场景:系统需要动态选择几种算法来实现功能时
- 模板模式(Template Pattern)
- 概述:定义一个操作算法的骨架,将一些步骤推迟到子类中实现
- 优点:增强了系统复用性
- 缺点:模板类不易拓展
- 使用场景:实现一个流程中有共性又有差异时
- 访问者模式(Visitor Pattern)
- 概述:表示一个作用于对象结构中的个元素的操作
- 优点:解耦了访问者(数据操作)与访问对象(数据结构)的关系,便于访问者的拓展
- 缺点:访问对象难以修改
- 使用场景:在不改变对象的前提下,需要对一个对象进行许多不相关的操作
结尾
实践是检验真理的唯一标准。在了解了相关设计模式后,日后还需要在实践中慢慢参悟。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名,转载请标明出处
最后编辑时间为:
2019-12-22