Fork me on GitHub

《设计模式-可复用面向对象软件的基础》简单概括

设计模式是一种“小框架”,即体系结构。尝试使用简短的语言描述23种设计模式。

重要原则:

  • 针对接口编程,而不是针对实现编程。
  • 继承产生了依赖,破坏了封装性。
  • 优先使用对象组合,而不是类继承。(组合往往难以实现,但是易于维护,拥抱了变化)
  • 类继承是白箱复用,对象的组合是黑箱复用。
  • 灵活性和可变性是简单性和高性能的敌人。
  • 不修改源码的原则。

模式介绍:

注意:以下的“用户”指的是使用对象的程序员,并非最终使用应用的用户。

创建型模式(通常从工厂办法开始,后面重构):

  • 抽象工厂(abstract factory):
    用户不直接创建一个产品对象,而是通过一个工厂对象间接创建。(用户与实际实现分离)
  • 生成器(builder):
    通过生成器一步步生成一个复杂产品对象。(生成器中维护一个产品对象,一直对产品进行升级,最后返回)
  • 工厂办法(factory method):
    用户通过工厂办法实例化产品对象。(抽象工厂也是使用工厂办法实例产品对象的)
  • 原型(prototype):
    每个对象都实现了clone方法,调用对象的clone就可以深拷贝出新的对象,同时可以通过参数自定义
  • 单例(singleon):
    一个类只有一个对象,并通过类方法获取到对象,实现对数据状态的共享。(全局变量)

结构型模式:

  • 适配器(adapter):
    已经有了两种接口的类,但是用户希望使用同一个的方式使用,在不改类源码的基础上对一个者类进行包装,让它表现出另一种类的接口,这个包装类就是适配器。(可以类比不同国家的插座,用户是用电器)
  • 桥接(bridge):
    将若干类聚合在一个桥接类中,小类可以单独发展,不影响桥接类。(多继承改成聚合,和适配器模式是在生命的不同周期的不同叫法)
  • 组合(composite):
    使用递归的方式实现树形结构,在一个对象中包含相同类实例的对象
  • 装饰(decorator):
    在不影响原本类的基础上,对一个实例对象动态增加功能。(将对象传给装饰类(和原类有同样的接口),并实例出新的对象)
  • 外观(facade):
    基金是股票的外观,通过高级接口封装子系统。
  • 享元(flyweight):
    为了防止对象过多,可以共享细粒度的对象(类似String常量池)
  • 代理(proxy):
    代理一个对象的访问,类似于适配器模式,不过代理是主动设计,适配器是事后补救。(保护对象,解耦)

行为型模式:

  • 职责链(chain of responsibility):
    每个对象中有下一个级别的对象,当用户的一个调用目前的对象无法满足的时候会调用下一个对象,形成了一条一直测试能否执行的链,直到被解决或者到了最后一个。(用户的调用不能保证处理,有关部门的感觉)
  • 命令(command):
    用户的请求是一个命令对象,将命令提交给处理的对象,然后对命令进行队列处理,类似事务(增加,删除)。(餐厅:一般的请求类似于喊一句老板给我来碗面,而命令模式类似于给老板一张勾选好的菜单)
  • 解释器(interpreter):
    定义一个翻译器,将用户的请求翻译成明确的行为
  • 迭代器(iterator):
    一个对象内部聚合了多个对象,使用暴露出来的方法顺序访问内部对象(多种遍历方式)。类似于一个next()方法。(游标的感觉)
  • 中介者(mediator):
    转发者,各个对象不必相互引用,只需要引用相同的中介者,由中介者转发操作。(降低了耦合)
  • 备忘录(memento):
    将对象中的状态属性复制成一个备忘录对象,并交给负责人对象保存,如果需要恢复就从负责人那里获取(类似于悔棋,撤回等操作,相比直接存储整个对象,使用备忘录存比较经济)
  • 观察者(observer):
    订阅或者依赖关系,当发布者发布了新的内容,订阅者都响应操作。实现:发布者维护一个订阅者列表,当发布者发布涉及订阅者的内容时,使用订阅者引用调用响应的方法。
  • 状态(state):
    为对象设置不同的状态,当用户调用相同的方法时,表现出来的效果依赖当前对象的状态。(类似于王者荣耀中的移动,当不同状态下:受控,疾跑等,移动速度不同)
  • 策略(strategy):
    将算法封装成对象使用,使得算法可以发展可以更换
  • 模板办法(template method):
    父类只是骨架,子类继承实现不同的行为
  • 访问者(visitor):
    对象写一个固定方法(参数为访问者),并调用访问者(对象作为参数)。这样,在访问者中就可以访问原对象中的方法了。如果需求有变化,只需要修改访问者即可。
-------------    本文结束  感谢您的阅读    -------------