常用设计模式


1. 设计原则

1、在超类中加上新的行为,会使得某些并不适合该行为的子类也具有该行为。

因此为了复用而使用继承,并不完美。

设计原则1

找到应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

设计原则2

针对接口编程,而不是针对实现编程。

充分利用多态的特性,变量的声明类型应该是一个超类型,通常是一个抽象类或者是一个接口。

2. 设计模式详解

2.10 观察者模式

(1)定义

观察者模式(Observer Pattern)定义了对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
观察者模式是一种对象行为型模式。
观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
细究的话,发布订阅和观察者有些不同,可以理解成发布订阅模式属于广义上的观察者模式。

(2)UML图

角色介绍:

  • Subject(目标):被观察者,它是指被观察的对象。 从类图中可以看到,类中有一个用来存放观察者对象的Vector 容器(之所以使用Vector而不使用List,是因为多线程操作时,Vector在是安全的,而List则是不安全的),这个Vector容器是被观察者类的核心,另外还有三个方法:attach方法是向这个容器中添加观察者对象;detach方法是从容器中移除观察者对象;notify方法是依次调用观察者对象的对应方法。这个角色可以是接口,也可以是抽象类或者具体的类,因为很多情况下会与其他的模式混用,所以使用抽象类的情况比较多。
  • ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知。同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
  • Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法 update(),因此又称为抽象观察者。
  • ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者 Observer 中定义的 update()方法。通常在实现时,可以调用具体目标类的 attach() 方法将自己添加到目标类的集合中或通过 detach() 方法将自己从目标类的集合中删除。

(2)优缺点

优点

  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系
  • 目标与观察者之间建立了一套触发机制
  • 支持广播通信
  • 符合“开闭原则”的要求

缺点

  • 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用
  • 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率

(3)相关实现

Spring 事件驱动模型也是观察者模式很经典的应用。就是我们常见的项目中最常见的事件监听器。

2.11 访问者模式

(1)定义

访问者模式的使用场景:

  • 对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。

(2)UML图

角色介绍

  • Visitor:接口或者抽象类,定义了对每个 Element 访问的行为,它的参数就是被访问的元素,它的方法个数理论上与元素的个数是一样的,因此,访问者模式要求元素的类型要稳定,如果经常添加、移除元素类,必然会导致频繁地修改 Visitor 接口,如果出现这种情况,则说明不适合使用访问者模式。
  • ConcreteVisitor:具体的访问者,它需要给出对每一个元素类访问时所产生的具体行为。
  • Element:元素接口或者抽象类,它定义了一个接受访问者(accept)的方法,其意义是指每一个元素都要可以被访问者访问。
  • ElementA、ElementB:具体的元素类,它提供接受访问的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
  • ObjectStructure:定义当中所提到的对象结构,对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素提供访问者访问。

(3)优缺点

我们要根据具体情况来评估是否适合使用访问者模式,例如,我们的对象结构是否足够稳定,是否需要经常定义新的操作,使用访问者模式是否能优化我们的代码,而不是使我们的代码变得更复杂。

优点

  • 各角色职责分离,符合单一职责原则
    通过UML类图和上面的示例可以看出来,Visitor、ConcreteVisitor、Element 、ObjectStructure,职责单一,各司其责。
  • 具有优秀的扩展性
    如果需要增加新的访问者,增加实现类 ConcreteVisitor 就可以快速扩展。
  • 使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化
    员工属性(数据结构)和CEO、CTO访问者(数据操作)的解耦。
  • 灵活性

缺点

  • 具体元素对访问者公布细节,违反了迪米特原则
    CEO、CTO需要调用具体员工的方法。
  • 具体元素变更时导致修改成本大
    变更员工属性时,多个访问者都要修改。
  • 违反了依赖倒置原则,为了达到“区别对待”而依赖了具体类,没有以来抽象
    访问者 visit 方法中,依赖了具体员工的具体方法。

参考文献

(1)观察者模式:https://juejin.cn/post/6844904100459446285

(2)访问者模式:https://www.jianshu.com/p/1f1049d0a0f4

作者

lei.ch1941

发布于

2023-09-25

更新于

2024-04-10

许可协议

评论