- 本博客为哈工大计算机科学与技术学院大二软件构造课程的课件翻译。同时记录了部分本人上课时的学习笔记和感悟
- 该博客9300字左右,主题为5-2面向可维护性的设计模式,已经全部更新完成
- 由于水平有限,翻译可能不是特别流畅、通顺,并且存在一定错误,观点、笔记不一定完全正确,敬请各位批评指正!
大纲
- 创建者模式
- 工厂方法模式创建对象而不指定要创建的确切类。
- 抽象工厂模式将具有共同主题的对象工厂分组。
- 结构型模式
- 代理为另一个对象提供了一个占位符来控制访问、降低成本和降低复杂性。
- 行为型模式
- 观察者模式是一种发布/订阅模式,允许多个观察者对象查看一个事件。
- 访问者模式通过将方法的层次结构移动到一个对象中来将算法与对象结构分离。
- 设计模式的共性和差异
阅读材料
- CMU 17-214:Nov 26
- 设计模式:第3.1、3.2、3.3、4.2、4.3、4.7、5.5、5.7、5.11、(5.1)、 (5.2)节
- 阅读是学习理解的关键
1、创建者模式
(1)工厂方法模式
工厂方法
- 也被称为“虚拟构造函数”(虚拟构造器)
- 意图:
- 定义一个用于创建对象的接口,但是让子类决定实例化哪个类。
- 工厂方法允许类将实例化推迟到子类。
- 什么时候我们应该使用工厂法?- - - - -当一个类是以下几种情况时:
- 不能预测它需要创建的对象的类
- 希望它的子类指定它创建的对象
- 将职责委托给多个帮助器子类之一,您需要本地化哪个帮助器是委托的知识。
- 优点:
- 消除了将特定于应用程序的类绑定到代码的需要。
- 代码只处理产品接口(跟踪),因此它可以处理任何用户定义的具体产品(FileTrace、SystemTrace)
- 潜在的缺点
- 客户可能必须创建Creator的子类,这样他们才能创建特定的具体产品。
- 如果客户端无论如何都必须子类化创建者,这是可以接受的,但是如果不这样,客户端就必须处理另一个演化点
- Open-Closed Principle (OCP) 开闭原则——对扩展的开放,对修改已有代码的封闭
(2)抽象工厂模式
抽象工厂模式
- 例1:考虑一个支持不同操作系统的多种外观和感觉标准的用户界面工具包:(一个UI, 包含多个窗口控件,这些控件在不同的OS中实现不同 )
- 如何为这些窗口管理器编写单个用户界面并使其可移植到不同的外观和感觉标准?
- 例2:考虑一个智能住宅的设施管理系统,它支持不同的控制系统:(一个仓库 类,要控制多个设备,这些设备的制造商各有不同,控制接口有差异 )
- 如何编写一个独立于制造商的控制系统?
- 抽象工厂模式提供了一个接口,用于在不指定具体类的情况下创建相关或依赖对象的族。(抽象工厂模式:提供接口以创建一组相关/相互依赖的对象, 但不需要指明其具体类。)
- 名称:抽象工厂(或工具包)
- 目的:允许创建独立于实现的相关对象家族
- 方法:使用工厂返回可用于创建相关对象集的工厂
- 适用性
- 保持独立于初始化或表示的不同系列的组件(产品)
- 必须以相互排斥和一致的方式使用
- 向客户隐藏多个家庭的存在
- 制造商独立
- 应对即将到来的变化
(1)代理模式
- 目标:
- 防止对象被其客户端直接访问
- 通过充当实体或占位符对象的传递,允许进行对象级访问控制。
- 解决方案:
- 使用一个称为代理的附加对象
- 客户端只能通过代理访问受保护的对象
- 代理跟踪受保护对象的状态和/或位置
- 某个对象比较“敏感”/“私密”/“贵重”,不希望被client直接访问 到,故设置proxy,在二者之间建立防火墙。
代理模式VS适配器模式
- 适配器:结构模式,目的:消 除不兼容,目的是B以客户端期望的统一的方式与A建立起联系。
- 典型的实现是一个包装类或一组类。
- 其目的不是为了方便将来的接口更改,而是为了方便当前的接口不兼容。
- 代理:行为模式,也使用包装器类,但目的是为实际资源创建一个替身。(目的:隔离对复杂 对象的访问,降低难度/代价,定位在“访问/使用行为” )
- 实际资源驻留在远程计算机上(代理促进了与远程资源的交互)
- 真正的资源创建起来是昂贵的(代理确保除非/直到真正需要时才会产生成本)
- 代理为它所替代的实际资源提供了一个临时替代,因此它必须提供相同的接口。
(1)观察者模式
- 问题:从属的状态必须与主的状态一致
- 解决方案:定义四种对象:
- 抽象主题:维护家属列表;当主更改时通知他们
- 抽象观察者:定义用于更新依赖项的协议
- 具体主题:家属数据管理;当主更改时通知他们
- 具体观察者:在收到更新消息后获得新的主题状态
- “粉丝”对“偶像”感兴趣,希望随时得知偶像的一举一动
- 粉丝到偶像那里注册,偶像一旦有新闻发生,就推送给已注册的粉丝 (回调callback粉丝的特定功能)
(2)访问者模式
- 访问者模式:允许在运行时对一组对象应用一个或多个操作,从而将操作与对象结构分离。( 对特定类型的object的特定操作(visit),在运行时将 二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类 )
- 访问者模式实际做的是创建一个使用其他类中的数据的外部类。
- 如果操作的逻辑发生了变化,那么我们只需要在visitor实现中进行更改,而不是在所有的item类中进行更改。
- 本质上:将数据和作用于数据上的某种/些特定操作分离开来。
- 为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码 可以在不改变ADT本身的情况下通过delegation接入ADT
- Iterator:行为模式,用于顺序访问聚合而不暴露其底层表示。因此,您可以在迭代器后面隐藏列表或数组或类似的聚合。
- 迭代器:以遍历的方式访问集合数据而无需暴露其内部表示,将“遍历”这项功能委派到外部的迭代器对象。
- 访问者:行为模式,用于在不改变元素本身实现的情况下对元素结构执行操作。
- 在特定ADT上执行某种特定操作,但该操作不在ADT内部实现,而是委托到独立的游客对象,客户端可灵活扩展/改变游客的操作算法,而不影响ADT
- Visitor:行为模式
- Strategy:行为模式
- 二者都是通过delegation建立两个对象的动态联系
- 但是Visitor强调是的外部定义某种对ADT的操作,该操作于ADT自身关系 不大(只是访问ADT),故ADT内部只需要开放accept(visitor)即可,client 通过它设定visitor操作并在外部调用。
- 而Strategy则强调是对ADT内部某些要实现的功能的相应算法的灵活替换。 这些算法是ADT功能的重要组成部分,只不过是delegate到外部strategy类 而已。
- 区别:visitor是站在外部client的角度,灵活增加对ADT的各种不同操 作(哪怕ADT没实现该操作),strategy则是站在内部ADT的角度, 灵活变化对其内部功能的不同配置。
4 设计模式的共性与差异性
设计模式的对比:共性样式1
适配器模式
代理模式
模板模式
设计模式的对比:共性样式2
策略模式
迭代器模式
工厂模式
抽象工厂模式
观察者模式
访问者模式
总结
- 创建者模式
- 工厂模式,抽象工厂模式
- 结构型模式
- 代理器模式
- 行为型模式
- 观察者模式,访问者模式