5.3 面向复用的设计模式

5.3 面向复用的设计模式

  • 1. 结构型模式
    • 1.1 适配器模式
    • 1.2 装饰器模式
    • 1.3 外观模式
  • 2. 行为类模式
    • 2.1 策略模式
    • 2.2 模板模式
    • 2.3 迭代器

综述:本节介绍几种典型的“面向复用”的设计模式
为什么要提出可复用的设计模式?
设计模式:软件设计中给定上下文中常见问题的一般可重用解决方案,除了类本身,设计模式更强调多个类/对象之间的关系和交互过程—比接口/类复用的粒度更大

1. 结构型模式

1.1 适配器模式

  1. 将某个类/接口转换为client期望的其他形式,也叫包裹器
  2. 通过增加一个接口,将已存在的子类封装起来,client面向接口编程,从而隐藏了具体子类。(具体是通过delegation的方法封装的)
  3. 本质上就是迎合client
  4. 但最终是面向接口编程,新加的类也要实现总的接口
  5. 实例:
    封装前:
    5.3 面向复用的设计模式_第1张图片
    封装后:
    5.3 面向复用的设计模式_第2张图片

1.2 装饰器模式

  1. 解决的问题:为对象增加不同侧面的特性,但不想通过继承来实现(继承会导致组合爆炸)
  2. 解决方法:对每一个特性构造子类,通过委派机制增加到对象上,装饰器同时用了分型和委托
  3. 具体实现:客户端需要一个具有多种特性的object,通过一层一层的
    装饰来实现
  4. 优点:更加灵活,且更容易组合
    5.3 面向复用的设计模式_第3张图片
  5. 实例:
    接口和抽象类的定义:
    5.3 面向复用的设计模式_第4张图片
    实现了具体的子类(super是核心,相当于在构造时沿用上一层的构造,不断迭代,并且添加了该子类的特有的功能):
    5.3 面向复用的设计模式_第5张图片
    客户端:
    5.3 面向复用的设计模式_第6张图片
  6. 装饰器模式和静态继承的区别:
    1. 装饰器运行时组合特性,而继承时编译时就确定了
    2. 装饰器由多个协作对象组成,而继承是创造了一个单一的,结构清晰的对象
    3. 装饰功能可以灵活的实现和组合,而基于继承的组合十分困难

1.3 外观模式

  1. 解决的问题:客户端需要通过一个简化的接口来访问复杂系统内的功能
  2. 方法:提供一个统一的接口来取代一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用
  3. 优点:便于客户端学习使用,解耦,它还促进子系统与其潜在的多个客户端的分离。
  4. 实质,把所有api放到一个方法里,然后api具体实现时要各种判断
  5. 实例:
    单独的api:
    5.3 面向复用的设计模式_第7张图片
    用外观模式:
    5.3 面向复用的设计模式_第8张图片
    客户端的代码:
    5.3 面向复用的设计模式_第9张图片
  6. 从实现中我们可以发现,开发者的实现工作量加大,要对client的不同的输入进行不同的判断

2. 行为类模式

2.1 策略模式

  1. 解决问题:针对特定任务存在不同的算法,但客户端可以在运行时根据动态上下文在算法之间切换。(黑盒框架)
  2. 方法:为算法创建一个接口,为算法的每个变体提供一个实现类。
  3. 优点:
    1. 方便扩展新的算法实现
    2. 将算法与客户端的上下文分离
  4. 实质:客户端用统一的接口调用它向需要的算法
  5. 实例:
    问题的总类图:其中paymentstrategy就是算法的接口
    5.3 面向复用的设计模式_第10张图片
    实例代码:
    5.3 面向复用的设计模式_第11张图片
    另一个实例代码和管理类:可以看到管理类在pay时把接口传了进来,即委托的方式
    5.3 面向复用的设计模式_第12张图片
    客户端:客户端在调用时要选择具体的算法
    5.3 面向复用的设计模式_第13张图片

2.2 模板模式

  1. 解决问题:做事情的步骤一样,但具体方法不同 (白盒框架)
  2. 方法:共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现,对于每一个具体的步骤,子类可能有不同的实现
  3. 本质:父类把解决问题的步骤罗列出来,然后设计不同的子类去实现这几个步骤,客户端调用的时候按照父类罗列的顺序去调用
  4. 使用继承和重写实现模板模式
  5. 实例:
    总类图:
    5.3 面向复用的设计模式_第14张图片
    抽象类代码:
    5.3 面向复用的设计模式_第15张图片
    子类实现父类代码、在客户端中的调用:
    5.3 面向复用的设计模式_第16张图片

2.3 迭代器

  1. 解决问题:客户端希望遍历被放入容器/集合类的一组ADT对象,无需关心容器的具体类型,也就是说不管放到哪里,都应该提供同样的遍历方式
  2. 方法:让自己的集合类实现Iterable接口,并实现自己的独特Iterator迭代器(hasNext, next, remove),允许客户端利用这个迭代器进行显式或隐式的迭代遍历
  3. 本质:让自己的集合类先实现一个xxxable的接口,这个接口里有一个方法会返回一个xxxtor的器,这样你的集合类就具有了这个器
  4. 优点:
    1. 隐藏底层容器的内部实现
    2. 支持具有统一接口的多种遍历策略
    3. 易于更换容器类型
    4. 促进程序各部分之间的沟通
  5. 实例:
    5.3 面向复用的设计模式_第17张图片

你可能感兴趣的:(软件构造)