23种设计模式
23种设计模式总结
设计模式分为三大类分别是创建型,行为型,结构型
创建型:
工厂模式
定义一个用于创建对象的接口, 让子类决定实例化哪个类
工厂方法使一个类的实例化延迟到其子类
抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口, 而无需指定他们具体的类
- 优点: 易于交换产品, 具体工厂配置不同的产品
- 优点: 让具体的创建实例过程与客户端分离, 客户端是通过它们的抽象接口操纵实例, 产品的具体类名也被具体工厂的实现分离, 不会出现在客户端的代码
建造者模式
将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示
- 用户只需指定需要建造的类型, 不需要知道具体地建造过程和细节
- 建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式
- 可替换性
单例模式
保证一个类仅有一个实例, 并提供一个访问他的全局访问点
- 确保任何情况下绝对只有一个实例
坑:
- 多进程, 要考虑加锁
- web时, 往往是多进程起
- web时, 扩容时还往往是多机器多实例
原型模式
用原型实例指定创建对象的种类, 并且通过拷贝这些原型创建新的对象
- 原型模型其实是从一个对象再创建另外一个可定制的对象, 而且不需要知道任何创建细节
- 一般在初始化信息不发生变化的情况下, 克隆是最好的办法, 既隐藏了对象创建的细节, 有提高了性能
在不指定类名的前提下生成实例
- 对象种类繁多, 无法将它们整合到一个类中
- 难以根据类生成实例时
- 解耦框架与生成实例: 让框架不依赖于具体的类, 不能指定类名来生成实例, 要实现注册一个原型
然后, 通过复制该实例来生成新的实例
总结:创建型设计模式用来创建新的对象,如果创建对象的流程相对简单,可以考虑使用工厂模式,
如果创建对象的过程比较繁琐,可以考虑使用建造者模式。
如果对象是全局唯一的,那么考虑使用单例模式。
如果只是想对已有对象进行复制(深拷贝和浅拷贝),那么考虑使用原型模式。
结构型:
适配器模式
一个类的接口转换成客户希望的另一个接口.
使得原本由于接口不兼容而不能work的那些类可以work. 用于填补'现有功能'和'所需功能'之间差异
- 适用: 系统的数据和行为都正确, 但是接口不符时. (已存在, 但是其接口和需要的不同)
- 适用: 当前现有的已经被充分测试, 并且已经被其他很多系统调用, 此时不宜修改, 但是又必须加入新功能用于满足某些需求
- 主要用于, 希望复用一些现存的类, 但接口又与复用环境要求不一致的情况
- 客户代码可以统一调用同一接口, 简单直接紧凑
- 可以再完全不改变现有代码的前提下, 使现有代码适配于新的接口
桥接模式
将抽象部分与它的实现部分分离, 使它们都可以独立地变化
- 独立变化
组合模式
将对象组合成树状结构以表示`部分-整体`的层次结构
使得用户对单个对象和组合对象的使用具有一致性
- 适用: 需求中体现部分与整体层次的结构, 希望用户可以忽略组合对象与单个对象的不同, 统一地使用组合结构中的所有对象时, 就应该考虑使用组合模式
- 优点: 让用户可以一致性的使用组合结构和单个对象
装饰模式
动态地给一个对象添加一些额外的职责,
就增加功能来说, 装饰模式比生成子类更为灵活
- 装饰模式, 是为已有功能动态地添加更多功能的一种方式
- 有效地将核心职责和装饰功能区分开
外观模式
为子系统中的一组接口提供一个一致的界面.
定义了一个高层接口, 是的这一子系统更加容易使用
- 统一接口人
- 减少依赖
享元模式
运用共享技术有效地支持大量细粒度的对象
- 可以避免大量非常相似类的开销
- 把区分的参数放在类实例外面, 在方法调用时传递进去
代理模式
为其他对象提供一种代理以控制这个对象的访问
总结:结构型设计模式重点在于类和对象之间的组合
常用的有代理模式、桥接模式、装饰器模式、适配器模式
代理模式和装饰器模式很类似,但是代理模式一般为类或者对象添加与功能无关的行为。而装饰器模式一般是添加新功能。
适配器模式一般用来对新老接口进行适配,对缺少或者多余的参数进行修改。
桥接模式一般用来解耦大的对象。
行为型:
观察者模式
定义类一种一对多的依赖关系, 让多个观察者对象同时监听某一个主题对象, 这个主题对象在发生变化时, 会通知所有观察者对象, 使它们能够自动干呢更新自己
- 适用: 当一个对象的改变需要同时改变其他对象时
- 解耦合, 让耦合的双方依赖于抽象, 而不是依赖于具体
模板方法模式
定义一个操作中的算法的构架, 而将一些步骤的实现延迟到子类中
这样, 可以使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤(相当于, 只需要覆写某些方法)
- 在父类中定义处理流程的框架, 在子类中实现具体处理的模式
- 在抽象类阶段确定处理的流程
- 使用继承改变程序的行为
- 把不变行为放到超类, 去除子类中的重复代码
- 提供了一个很好地代码复用平台
命令模式
讲一个请求封装为一个对象, 从而使你可用不同的请求对客户进行参数化
对请求排队或记录请求日志, 以及支持可撤销操作
- 比较容易设计一个命令队列
- 在需要情况下, 可以将命令计入日志
- 允许接受请求的一方决定是否要否决请求
- 可以容易的实现对请求的撤销和崇左
- 由于加紧新的具体命令类不影响其他类, 可以很容易新增
- 把请求一个操作的对象与指导怎么执行一个操作的对象分隔开
状态模式
当一个对象的内在状态改变时, 允许改变其行为. 这个对象看起来更像是改变了其类
- 解决: 当控制一个对象状态转换的条件表达式过于复杂的情况,
把状态的判断逻辑转移到表示不同状态的一系列类中, 可以把复杂的判断逻辑简单化
- 好处: 将与特定状态相关的行为局部化, 并且将不同状态的行为分割开来
- 通过定义新的子类, 可以很容易地增加新的状态和转换
- 消除庞大的条件分支语句, 减少相互间的依赖, 把各种状态转移逻辑分布到了State的子类之间
- 适用: 当一个对象的行为取决于它的状态, 并且它必需在运行时刻根据状态改变其行为时, 使用状态模式
责任链模式
使多个对象都以机会处理请求, 从而避免请求的发送者和接受者之间的耦合关系
将这个对象连成一条链, 沿着这条链传递请求, 直到有一个对象处理它为止
- 可以随意增加或修改处理一个请求的链式结构
解释器模式
给定一个语言, 定义他的文法的一种表示, 并定义一个解释器, 这个解释器使用该表示来解释语言中的句子
- 解决: 如果一种特定类型问题发生的频率足够高, 那么可能就值得将该问题的各个实例表述为一个简单语言中的句子,
这样就可以构建一个解释器, 该解释其通过解释这些句子来解决该问题
- 适用: 当有一个语言需要解释执行, 并且你可以将该语言中的句子表示为一个抽象语法树时
- 好处: 容易改变和扩展文法
- 不足: 需要为文法中的每一条规则至少定义一个类, 可能难以维护和管理
中介者模式
用一个中介对象来封装一系列的对象交互
中介者使各对象不需要显示的相互引用, 从而使耦合松散, 可以独立地改变他们之间的交互
- 多对多交互
- 把对象如何写作进行了抽象
访问者模式
标识一个作用于某对象结构中的各元素的操作
可以使你在不改变各元素类的前提下定义作用于这些元素的新操作
- 适用于数据结构相对稳定的系统, 把数据结构和作用于结构上的操作之间的耦合解脱开, 是的操作集合可以相对自由地演化
- 目的是: 把处理从数据结构分离出来, 有比较稳定的数据结构, 又有易于变化的算法
- 优点: 增加新的操作很容易, 等同于增加一个新的访问者
策略模式
它定义了算法家族, 分别封装起来, 让他们之间可以互相替换, 此模式让算法的变化, 不会影响到使用算法的客户
- 策略模式是一种定义一系列算法的方法, 从概念上来讲, 所有算法完成的都是相同的工作, 只是实现不同,
它可以以相同的方式调用所有的算法, 减少各种算法与算法类之间的耦合
- 策略模式的Strategy类层次位Context定义了一系列的可供重用的算法或行为, 继承有助于析取出这些算法中的公用功能
- 优点: 简化了单元测试, 每个算法有自己的类, 可以通过自己的接口单独测试
- 解决: 不同行为堆砌在同一个类中, 很难避免使用条件语句, 通过Strategy消除之
- 作用: 封装算法/业务规则等
备忘录模式
在不破坏封装性的前提下, 捕获一个对象的内部状态, 并在该对象之外保存这个状态
这样以后可以将该对象恢复到原先保存的状态
- 将要保存的细节封装到memento中
- 比较适合功能比较复杂, 需要维护或记录属性的历史类, 或者需要保存部分属性
- 例如: 保存历史命令, 并执行撤销操作
- 备忘录可以把复杂的对象内部信息对其他对象屏蔽起来
迭代器模式
提供一种方法顺序地访问一个聚合对象中的各个元素, 而又不暴露改对象的内部表示
- 无差别遍历聚合对象
- 需要对聚集进行多种方式遍历时
- 分离了集合对象的遍历行为, 做到不暴露集合内部结构, 又可以让外部代码透明的访问集合内部的数据