设计模式学习总结

落下的都得补上。

  • 一张总结图起手

    20200908194129.jpg

相似的设计模式对比

  • 工厂模式 && 建造者模式
    • 工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象
    • 建造者模式是用来创建一种类型的复杂对象,可以通过设置不同的可选参数,“定制化”地创建不同的对象
    • 比喻
      • 工厂模式:土豆,面粉,番茄
      • 建造者模式:披萨
  • 策略模式 && 命令模式
    • 在策略模式中,不同的策略具有相同的目的、不同的实现、互相之间可以替换。比如,BubbleSort、SelectionSort 都是为了实现排序的,只不过一个是用冒泡排序算法来实现的,另一个是用选择排序算法来实现的。而在命令模式中,不同的命令具有不同的目的,对应不同的处理逻辑,并且互相之间不可替换
  • 单例模式 && 享元模式 && 缓存 && 静态工厂方法

    • 他们的共同点是:对象的复用
    • 不同点:
      • 应用享元模式是为了对象”共享使用”,节省内存
      • 而应用单例/多例模式是为了限制对象的个数
      • 应用缓存是为了提高访问效率
      • 应用对象池(数据库连接池,线程池)是为了对象的”重复使用”和管理,主要是为了节省时间
      • 有一种方法叫 静态工厂方法,例如 Boolean.valueof(),不会在每次调用时返回一个新对象,而是复用已有的,这一点有点像享元模式
  • 适配器 && 代理 && 装饰器 && 桥接,:

    • 他们的共同点是:对方法的增强
    • 不同点:
      • 适配器模式的作用是”适配”,通常用于适配不同的组件,新旧系统
      • 桥接模式将接口部分和实现部分分离,使两者可以分别扩展
      • 装饰者模式是对原始类功能进行增强,并且可以支持多次,多种增强
      • 代理模式实现了代理类和原始类的解耦,使代理类可以用于增强不同的功能
  • 策略模式 && 简单工厂模式 && 命令模式:

    • 共同点:都有对if/else进行下沉
    • 不同点:
      • 策略模式根据运行时状态返回一个”策略”/“算法”,这些”策略”具有相同目的,比如BubbleSort、SelectionSort 都是为了实现排序
      • 命令模式中不同的命令具有不同的目的,对应不同的处理逻辑,并且互相之间不可替换
      • 而简单工厂更侧重返回一个创建的对象
  • 中介模式 && 观察者模式

    • 在观察者模式中,尽管一个参与者既可以是观察者,同时也可以是被观察者,但是,大部分情况下,交互关系往往都是单向的,一个参与者要么是观察者,要么是被观察者,不会兼具两种身份。也就是说,在观察者模式的应用场景中,参与者之间的交互关系比较有条理
    • 而中介模式正好相反。只有当参与者之间的交互关系错综复杂,维护成本很高的时候,我们才考虑使用中介模式。毕竟,中介模式的应用会带来一定的副作用,前面也讲到,它有可能会产生大而复杂的上帝类。除此之外,如果一个参与者状态的改变,其他参与者执行的操作有一定先后顺序的要求,这个时候,中介模式就可以利用中介类,通过先后调用不同参与者的方法,来实现顺序的控制,而观察者模式是无法实现这样的顺序要求的
  • 享元模式 && 单例 && 缓存 && 对象池

    • 享元模式跟单例
      • 在单例模式中,一个类只能创建一个对象,而在享元模式中,一个类可以创建多个对象,每个对象被多处代码引用共享。实际上,享元模式有点类似于之前讲到的单例的变体:==多例==
      • 尽管从代码实现上来看,享元模式和多例有很多相似之处,但从设计意图上来看,它们是完全不同的。应用享元模式是为了对象复用,节省内存,而应用多例模式是为了限制对象的个数
    • 享元模式跟缓存
      • 享元的“缓存”实际上是“存储”的意思
      • 通常意义上的缓存,主要是为了提高访问效率,而非复用
    • 享元模式跟对象池
      • 对象池、连接池、线程池等池化技术中的“复用”和享元模式中的“复用”实际上是不同的概念
      • 池化技术中的“复用”可以理解为“重复使用”,主要目的是节省时间,在任意时刻,每一个对象、连接、线程,并不会被多处使用,而是被一个使用者独占,当使用完成之后,放回到池中,再由其他使用者重复利用
    • 享元模式中的“复用”可以理解为“共享使用”,在整个生命周期中,都是被所有使用者共享的,主要目的是节省空间
  • 模板模式 && 回调

    • 从应用场景上来看,同步回调跟模板模式几乎一致。它们都是在一个大的算法骨架中,自由替换其中的某个步骤,起到代码复用和扩展的目的。而异步回调跟模板模式有较大差别,更像是观察者模式

    • 从代码实现上来看,回调和模板模式完全不同。回调基于组合关系来实现,把一个对象传递给另一个对象,是一种对象之间的关系;模板模式基于继承关系来实现,子类重写父类的抽象方法,是一种类之间的关系

    • 回调相对于模板模式会更加灵活

      • 像 Java 这种只支持单继承的语言,基于模板模式编写的子类,已经继承了一个父类,不再具有继承的能力
      • 回调可以使用匿名类来创建回调对象,可以不用事先定义类;而模板模式针对不同的实现都要定义不同的子类
      • 如果某个类中定义了多个模板方法,每个方法都有对应的抽象方法,那即便我们只用到其中的一个模板方法,子类也必须实现所有的抽象方法。而回调就更加灵活,我们只需要往用到的模板方法中注入回调对象即可

总结

  • 实际上,每个设计模式都应该由两部分组成:第一部分是应用场景,即这个模式可以解决哪类问题;第二部分是解决方案,即这个模式的设计思路和具体的代码实现。不过,代码实现并不是模式必须包含的。如果你单纯地只关注解决方案这一部分,甚至只关注代码实现,就会产生大部分模式看起来都很相似的错觉
  • 实际上,==设计模式之间的主要区别还是在于设计意图==,也就是应用场景。单纯地看设计思路或者代码实现,有些模式确实很相似,比如策略模式和工厂模式
-------------The End-------------
坚持原创技术分享,您的支持将鼓励我继续创作!