软件构造课程总结(十一)——面向可复用性和可维护性的设计模式


设计模式:针对软件设计中给定上下文中常见问题的一种通用的、可重用的解决方案。

除了类本身,设计模式更强调多个类/对象之间的关系和交互过程—比接口/类复用的粒度更大。

设计模式分类

  • 创建型模式:关注对象创建的过程
  • 结构型模式:处理类或对象的组合
  • 行为类模式:描述类或对象交互和分配责任的方式

创建型模式

工厂方法模式

也被称为“虚拟构造器”。

意图:

  • 定义用于创建对象的接口,但让子类决定要实例化哪个类。

  • 工厂方法允许类将实例化推迟到子类。

当client不知道要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。

请添加图片描述

工厂方法

  • 定义工厂类接口

  • 定义工厂类

  • 客户端使用时构造工厂类,然后利用工厂类生成对象

    (多一层封装,便于将生成对象的具体逻辑封装)

静态工厂方法

既可以在ADT内部实现,也可以构造单独的工厂类

使用静态方法,从而避免对工厂类的构造。

工厂方法优点:

  • 无需将特定于应用程的类绑定到代码中。
  • 代码仅处理产品接口,因此它适合任何用户定义的具体类

工厂方法潜在缺点:

  • 客户可能必须构造工厂类,这样他们才可以创建一个特定的对象。
  • 如果客户端必须对工厂类进行子类化,那么这是可以接受的,但如果不是,那么客户端就必须处理另一个演化点。

工厂方法满足OCP原则。

结构型模式

适配器模式

意图:将一个类/接口转换为客户端希望获得的另一个类/接口。

适配器模式允许类因为不兼容的接口而不能一起工作。

通过增加一个接口,将已存在的子类封装起来,client面向接口编程,从而隐藏了具体子类。

将旧组件重用到新系统(也称为“包装器”)。

请添加图片描述

适配器模式:

  • 新建一个接口,接口供客户端调用
  • 新建一个类实现接口,类将方法的实现委托给了原来的不匹配的类。

增加了一层调用,处理参数不匹配的情况。

装饰器模式

对同一个类有很多不同的子类继承它,每个子类需要实现不同的特性

每个子类的功能是功能集合的任意组合:比如对于A类有B1,B2,B3…等等子类,B1需要实现功能1、2、3,B2需要实现功能2,B3需要实现功能1、3…

继承的限制:如果为每一个组合创建一个类并定义一系列继承关系——

  1. 组合爆炸 2. 大量代码重复

请添加图片描述

装饰器模式

需求:需要对单个对象进行任意的或动态的可组合的扩展。

方法: 对每一个特性构造子类,通过委派机制增加到对象上

好处:比静态继承更灵活;可定制的、内聚的扩展

装饰器模式使用子类型和委托

请添加图片描述

装饰器模式:

  • 创建一个接口以及基础类,基础类实现接口,在基础类里面实现所有基础功能

  • 创建一个装饰器A,内部保有一个final的接口类型的对象,在装饰器的构造函数里传入并绑定。装饰器A实现接口,方法的基础逻辑委托给保有的对象实现。可以扩展方法逻辑或者添加新方法。

  • 如果客户端需要一个具有多种特性的object,则通过一层一层的装饰来实现,例:

    Stack t = new SecureStack(new SynchronizedStack(new UndoStack(s));

外层方法要具有内层方法并将实现委派给内层。

装饰和继承

  • 装饰器在运行时组成功能,继承会在编译时组成特性
  • 装饰器由多个协作对象组成,继承将生成一个类型清晰的对象
  • 可以混合和匹配多种装饰器,但继承只能是单重的

行为类模式

策略模式

需求:有多种不同的算法来实现同一个任务,但需要client根据需要动态切换算法,而不是写死在代码里。例:对客户列表进行排序(气泡排序、合并排序、快速排序)

解决方法:为不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例

好处:易于扩展新的算法实现;将算法与客户端上下文分离

请添加图片描述

策略模式:

  • 定义策略接口,执行逻辑的类通过的调用接口定义的策略方法
  • 为每一种可行方法定义一个方法类并继承策略接口
  • 客户端通过动态传入方法类来实现对不同方法的调用
模板模式

问题:一些客户共享相同的算法,但在具体细节上有所不同,即,一个算法由可定制的部分和不变的部分组成。公共步骤不应该在子类中被重复,而是需要被重用。做事情的一部分方法一样,但某一部分方法不同。

例:执行一个测试用例的测试套件——打开、阅读、撰写不同类型的文件。

解决方法:定义抽象类,共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现。子类为上述每个步骤提供了不同的实现。

模板方法和策略方法:

模板方法模式使用继承+重写方法来改变算法,适应不同场景需求;而策略模式则使用委托来改变算法(接口和特殊多态性)。

模板方法被广泛地应用于框架中。该框架实现了算法的不变量。

客户端定制为算法提供了专门的步骤。原则:“Don’t call us, we’ll call you”。

请添加图片描述

模板模式:

  • 定义模板类(抽象类)。确定通用逻辑,并直接实现在模板类内部。所有非通用逻辑采用抽象方法的方式定义。
  • 为每一种场景编写具体类,继承模板类并实现抽象方法。
  • 执行逻辑时传入具体类,并直接调用模板类方法即可。
迭代器模式

需求:客户端需要统一的策略来访问容器中的所有元素,而且独立于容器类型。也就是说,不管对象被放进哪里,都应该提供同样的遍历方式。

解决方法:采用迭代器模式,定义迭代器并支持按特定方式遍历容器内的元素。

好处:隐藏了底层容器的内部实现;支持具有统一接口的多种遍历策略;易于更改容器类型;方便了程序各部分之间的通信

迭代器结构:

  • 抽象的迭代器(迭代器接口)类定义了遍历协议
  • 每个容器类的具体迭代器(实现迭代器接口的方法)
  • 容器对象构造具体迭代器对象
  • 容器对象保留对具体迭代器对象的引用

请添加图片描述

Iterable接口:实现该接口的集合对象是可迭代遍历的

public interface Iterable<T> {
	...
	Iterator<T> iterator();
}

Iterator接口:迭代器

public interface Iterator<E> {
	boolean hasNext();
	E next();
	void remove();
}

迭代器模式:

  • 构造自己的独特Iterator迭代器并实现迭代器接口(hasNext, next, remove)

  • 使自己的集合类实现Iterable接口,在iterator()方法中返回自己构造的迭代器类型

  • 允许客户端利用这个迭代器进行显式或隐式的迭代遍历:

    隐式遍历:

    for (E e : collection) {}
    

    显式遍历:

    Iterator<E> iter = collection.iterator(); 
    while(iter.hasNext()) {}
    
访问者模式

访问者模式:对特定类型的object的特定操作(visit),在运行时将二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类。

  • 访问者模式实际上所做的是创建一个使用其他类中的数据的外部类。

  • 如果操作的逻辑发生了变化,那么我们只需要在访问者实现中进行更改,而不是在所有的类中进行更改。

本质上:将数据和作用于数据上的某种特定操作分离开来。

为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下通过delegation接入ADT。

请添加图片描述

访问者模式:

  • 定义Visiter接口以及相应的具体访问逻辑

  • 为ADT定义accept(visitor)方法,内部调用传入的visitor的访问方法,传入自身

访问者模式 & 策略模式

  • 二者都是通过delegation建立两个对象的动态联系

  • 但是Visitor强调是的外部定义某种对ADT的操作,该操作于ADT自身关系不大(只是访问ADT),故ADT内部只需要开放accept(visitor)即可,client通过它设定visitor操作并在外部调用。

  • 而Strategy则强调是对ADT内部某些要实现的功能的相应算法的灵活替换。这些算法是ADT功能的重要组成部分,只不过是delegate到外部strategy类而已。

区别:visitor是站在外部client的角度,灵活增加对ADT的各种不同操作(哪怕ADT没实现该操作),strategy则是站在内部ADT的角度,灵活变化对其内部功能的不同配置。

设计模式的共性与差异性

设计模式的对比:共性样式1

请添加图片描述

只使用“继承”,不使用委托。

核心思路:OCP/DIP(依赖反转,客户端只依赖“抽象”,不能依赖于“具体”)

发生变化时最好是“扩展”而不是“修改”。

例:Adapter,Template

请添加图片描述
请添加图片描述

设计模式的对比:共性样式2

请添加图片描述

两棵“继承树”,两个层次的委托。

例:Strategy,Iterator,Factory Method,Visitor

请添加图片描述

请添加图片描述
请添加图片描述
请添加图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梚辰

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值