设计模式的最核心的功能在于代码的扩展性和维护性,因此,很多设计模式在阅读的时候并不是很直接能了解到调用流程,我们只能从设计模式的产生和演进过程中来理解。

设计原则

  • 多用组合 少用继承
  • 尽量让交互对象松耦合
  • 分离程序中变化的部分和不变得部分
  • 针对接口编程 不针对实现编程
  • 依赖倒置原则
  • 依赖抽象 不依赖具体类
  • 最少知识原则(迪米特法则)
  • 好莱坞原则(不以子类角色调用父类方法,应该用父类角色调用子类实现或者重写的方法,防止“依赖腐败”)
  • 单一原则
  • 开闭原则 对修改关闭,对拓展开放

1、策略模式

1.1、基类的拆分、基于可变(接口)或不可变的水平拆分

公共属性继续保留
可变行为抽取为接口

优点:可变行为中子类可选择性的选择自己有的行为进行实现,而不用像继承那样必须继承不必要的方法(原则上是不允许的,相当于子类具备他不应该具有的能力或者属性)或者重写父类不满足的方法
缺点:关于子类自己的方法,父类引用是无法访问到的,而且,由于一个类可能实现多个行为接口和基类保留的不可变部分的行为或者属性,想要完全访问到子类的所有的方法或者属性,必须只能使用子类自己的实例,这样代码的可读性和拓展性将会变得很低,而且可能会出现大量的冗余代码

1.2、基于接口类型的属性拓展

试想将抽取出去的可变行为作为一个基类的实例变量,是不是可以通过这个引用来调取实现类的方法了,我们在构建这个类的时候,通过构造方法传递不同方法属性的实现即可。

优点:利用多态的思想实现了代码的拓展性,基于父类的引用方式调用子类的方法。实质上在拆分的思想上加了多态的思想
缺点:需要为使用到可变行为的实例注入他们需要的可变接口引用的实现类,某些可变行为在实际使用中可能是需要能发生改变的

1.3、多用组合少用继承

虽然现在我们把可变部分抽取成了一个借口类型的实例变量,并通过构造方法的方式对外提供具体的实现,但是,某些不需要的可变部分的接口类型可能并未被赋值而产生了空指针异常,或者这些可变部分在实际使用过程中需要设置新的值,或者在某些设计模式下不兼容,比如单利模式中,构造方法就是不对外提供的。
此时我们可以不采用构造方法的方式,而是将这些可变接口不作为构造参数传递,但是在设计的时候给与默认值,对外则提供setter的方式可供外界改值,而且对于null的情况需特殊处理。

2、观察者模式

观察者模式的要求是观察者和被观察者之间存在数据依赖关系,被观察者是持有数据的一方,观察者要依赖被观察者提供的数据,而且,观察者有多个,而被观察者只有一个。
数据依赖机制,通常,被观察者会将持有的数据推给观察者—>实质上是被观察者维护这观察者的列表,并不是所谓的推数据,而是被观察者使用观察者列表直接迭代调用update()方法
数据的获取方式一般有两种,一种是上面介绍的被观察者主动调用方法更新,这样的结果是观察者始终处于被动情况,所以在jdk中提供了一种观察者主动拉取数据的方式。

3、装饰器模式

增强接口,通过不断包装接口,在包装的同时可以增加新的功能以增强原来的接口的功能
装饰器模式是将基础对象经过装饰层层增强其功能,比如,对于某一类对象,有的属性或者行为可能是这些对象共有的,有的竖向属性或者行为可能只是某些对象特有的,如果用传统的继承的方式,就会出现某些对象本不该有的行为或者属性被继承了,所以,我们可以将最基本的部分的属性或者行为抽取出来,作为一个超类,然后,对于那些特有的行为或者属性,或者对于这些属性需要增强效果或者替换,我们可以利用包装的思想,

工厂模式

严格说工厂模式可以算作两种模式,工厂方法模式和抽象工厂模式,而简单工厂只能算作是一种变成思想,算不上是一种设计模式

简单工厂

4、工厂方法

5、抽象工厂

6、单例模式

恶汉式

dubbo check
单sync

7、命令模式

image.png
image.png

8、适配器模式

进行接口的转换,例如两个功能相似的接口,但是在设计的时候分离成不同的类型,由于类型的差异,导致两个接口不能直接替换使用,这样需要其中一个接口转换而去适配另外一个接口,一般,我们把更为“标准”(可以理解成通用性或者使用率较高的接口)当成被适配者,另外一个接口(适配者)通过适配器(进行转换)转换成可以被适配者能够使用的类型。

7.1、对象适配器

7.2、类适配器

9、外观模式

将多个接口的复杂操作转换成一些简单的操作,即,在实际过程中我们不需要再依次调用这些接口的方法,通过外观提供的简单方法去调用这些接口提供的方法。

10、模板方法模式

模板方法模式是对计算的封装(计算方法),使得所有子类都可以对这些固定模式的模板方法进行调用和扩展

固定算法采用final方式不让子类拓展(这个方法有个术语叫做原语操作)

需要子类自己提供算法逻辑的以抽象的方式让子类自己实现

流程控制或者分支控制的方法。父类给空实现或者默认返回值,子类可视情况进行拓展

11、迭代器模式

提供一种方法来访问集合对象中的各个元素,但又不会暴露集合的表示。

12、组合模式

组合模式允许将对象组合成树形结构来表现“整体/部分”层次结构,组合模式让客户以一致的方式处理个别对象和对象组合。

13、状态模式

允许对象在内部状态发生改变是改变它自己的行为,对象看起来好像是修改了它的类。
状态模式的实现是通过将状态抽象成不同的类,通过提供统一的接口让不同状态的类实现该接口,并在某些行为发生的时候更新对象的状态,然后再根据最新的状态判断用户执行的行为。
简单的理解,状态模式是通过接口统一所有的状态,而将不同的状态抽象成不同的状态类实现这个装态接口,这样在实际的运行阶段将状态通过组合的方式和实际的执行对象关联,在实际执行过程中,对象的行为就会像是将对象的状态从一个状态游走到另外一个状态,而实际上我们只不过是替换了状态接口引用的实际状态的状态实现而已。
image.png

状态模式和设计模式的对比

状态模式和设计模式在设计上几乎是一模一样,他们的区别在于状态模式在实际执行过程中需要维护状态的更新,再由最新的状态决定需要使用哪一个状态实现类执行接下来的操作
而策略模式需要你从组合接口的实现类中选择实际执行的操作交由哪一个实现类执行,不需要关心其他的东西。

image.png

14、代理模式