第六章:面向软件构造的可复用性的构建方法
第二节:设计可维护模式
问题一:可维护模式的分类
- 构建模式(Creational patterns)
- 结构模式(Structural patterns)
- 行为模式(Behavioral patterns)
问题二:构建模式(Creational patterns)
1.工厂模式方法(Factory Method pattern)
方法:定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。
用途:当client不知道要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。
理解:说到工厂方法,其实本质就是尽量避免Client使用SomeObject object = new SomeObject()这种可以直接使用new构建对象的方法。转而提供一些工厂类来避免暴露我的具体的类名。举个例子来说明,有一家餐馆,卖各种调料酱,这家店的老板告诉他的顾客,这些调料酱有沙拉酱,烧烤酱和番茄酱等等,但怎么要看顾客的使用就行;还有一家餐馆,老板不想让顾客知道我用的什么酱,我只告诉你你可以用调料酱。
上面两个例子,前面那个餐馆就可以视为没有工厂,直接用new来“使用酱”;后边的餐馆,就有一个工厂屏蔽了顾客和餐馆,只有餐馆的人知道我给你的啥酱。(转自https://blog.csdn.net/qq_37487121/article/details/79985899)
模式图:
*例:非静态的工厂方法:
静态的工厂方法:
优点:
– Eliminates the need to bind application-specific classes to your code.
– Code deals only with the Product interface (Trace), so it can work withany user-defined ConcreteProduct (FileTrace, SystemTrace)
潜在的缺点:
– Clients may have to make a subclass of the Creator, just so they cancreate a certain ConcreteProduct.
– This would be acceptable if the client has to subclass the Creator anyway,but if not then the client has to deal with another point of evolution.
满足:OCP(Open-Closed Principle):—对扩展的开放,对修改已有代码的封闭
2.抽象工厂模式(Abstract Factory)
方法:提供接口以创建一组相关/相互依赖的对象,但不需要指明其具体类。
用途:例:①当一个UI,包含多个窗口控件,这些控件在不同的OS中实现不同。②当一个仓库类,要控制多个设备,这些设备的制造商各有不同,控制接口有差异
理解:
**例:还是餐馆的例子,还有一家老板,比较死板,我不想让你顾客因为你要的酱不对影响我菜的味道,我规定你要了其中某种菜,只能再要与其搭配的那种酱,而不能要其他的酱。比如,我要了沙拉,想要酱那么我只提供沙拉酱;但是你有自由选择不要酱(即我利用Abstract Factory创建的不是一个完整的产品,而是一个产品族)。(转自https://blog.csdn.net/qq_37487121/article/details/79985899)
(***Abstract Factory 创建的不是一个完整产品,而是“产品族”(遵循固定搭配规则的多类产品的实例),得到的结果是:多个不同产品的object,各产品创建过程对client可见,但“搭配”不能改变。)
(本质上,Abstract Factory是把多类产品的factory method组合在一起)
*例:在Lab3中:
GraphPoet是由Word类型的顶点和WordNeighborhood类型的边组成的。
NetworkTopology是由Computer、Server、Router类型的点和NetworkConnection类型的边组成的。
***Vertex和Edge的子类,要有固定搭配,不能随意组合。
3.构造器模式(Builder)
方法:创建复杂对象,包含多个组成部分
理解:仍然是餐馆的例子,还有一家老板,死板但是良心,我觉得你要了我的菜只有搭配我的酱才会更好吃,所以我干脆你只要点了我的菜就认为你需要我的酱。比如,我要了薯条套餐,直接给我的就是薯条和番茄酱(Builder模式创建的是一个完整的产品,有多个部分组成,Client不需要知道我各个部分是怎样创建怎样组合的)。(转自https://blog.csdn.net/qq_37487121/article/details/79985899)
注意与抽象工厂进行区分:client要的不是一堆零散的objects (abstractfactory那样的结果),而是一个完整的产品,client不关心其中的细节组成部分是什么、如何创建。
模式图:
*例:
对比抽象工厂和构建(Abstract Factory vs Builder)
- Abstract Factory 创建的不是一个完整产品,而是“产品族”(遵循固定搭配规则的多类产品实例),得到的结果是:多个不同产品的实例object,各产品创建过程对client可见,但“搭配”不能改变。
- Builder 创建的是一个完整的产品,有多个部分组成,client不需了解每个部分是怎么创建、各个部分怎么组合,最终得到一个产品的完整object
**例:在Lab3中,四个图应用都要创建图对象,要为不同应用build出不同的vertex list和edge list。
问题三:结构模式(Structural patterns)
1. 桥接模式(Bridge)
方法:Bridge是OOP最基本的structural pattern,通过delegation+inheritance建立两个具体类之间的关系(DIP依赖转置,抽象依赖于抽象)
模式图:
*例:
桥接模式与策略模式的对比(Bridge vs. Strategy)
- Bridge: structural pattern 强调双方的run time delegation linking。一个类A的对象中有其他类B的对象作为其组成部分,但A的对象具体绑定到B的哪个具体子类的实现?在运行时通过delegation加以组合,并永久保存这种delegation关系。
- Strategy: behavioral pattern 强调一方run-time使用另一方的“算法”。“算法”通常实现为“类的某个方法”的形式,strategy的目的并非在“调用算法的类”与“被调用算法所在的类”之间建立起永久联系,而只是帮助前者临时使用后者中的“算法”,前者无需永久保存后者的实例。
- 理解:
2.代理模式(Proxy)
方法:
用途:某个对象比较“敏感”/“私密”/“贵重”,不希望被client直接访问到,故设置proxy,在二者之间建立防火墙。
模式:
*例:
代理模式与适配器对比(Proxy vs. Adaptor)
- Adapter: structural pattern, and the purpose is to change theinterface of class/library A to the expectations of client B. 目的:消除不兼容,目的是B以客户端期望的统一的方式与A建立起联系。
- Proxy: behavioral pattern, also uses wrapper classes, but thepurpose is to create a stand-in for a real resource. 目的:隔离对复杂对象的访问,降低难度/代价,定位在“访问/使用行为”
3.组合模式(Composite)
组合模式与装饰器的对比(Composite vs Decorator)
- Composite: structural pattern, allows you to build a hierarchicalstructure (tree) in a way that allows your external code to view theentire structure as a single entity. 目的是在同类型的对象之间建立起树型层次结构,一个上层对象可包含多个下层对象
- Decorator: structural pattern, too, allows an entity to completelycontain another entity so that using the decorator looks identical tothe contained entity. 强调的是同类型对象之间的“特性增加”问题,它们之间是平等的,区别在于 “拥有特性”的多少,每次decoration只能作用于一个object。
问题四:行为模式(Behavioral patterns)
1.观察器(Observer)
场景:“粉丝”对“偶像”感兴趣,希望随时得知偶像的一举一动;粉丝到偶像那里注册,偶像一旦有新闻发生,就推送给已注册的粉丝(回调callback粉丝的特定功能)
模式图:
*例:
2.Visitor
用途:对特定类型的object的特定操作(visit),在运行时将二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类
本质:将数据和作用于数据上的某种/些特定操作分离开来。
模式图:
*例:
对比Visitor vs Iterator
- Iterator: behavioral pattern:迭代器:以遍历的方式访问集合数据而无需暴露其内部表示,将“遍历”这项功能delegate到外部的iterator对象。
- Visitor: behavioral pattern:在特定ADT上执行某种特定操作,但该操作不在ADT内部实现,而是delegate到独立的visitor对象,客户端可灵活扩展/改变visitor的操作算法,而不影响ADT