零. 行为型模式概述
1.定义
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个独个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为,由于组合关系或聚合关系比继承关系耦合度低,满足合成复用原则,所以对象行为模式比类行为模式具有更大的灵活性。
2.包含以下11种模式
1.模板方法模式(Template Method):
定义一个操作中的算法骨架,将该算法的一些步骤延迟到子类中,使子类在不改变算法结构的情况下重定义算法的某些特定步骤。
2. 策略模式(Strategy Pattern):
定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。
3. 命令模式(Command pattern):
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。
4. 职责链模式(Chain of Responsibility Pattern):
把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。
5. 状态模式(State Pattern):
允许一个对象在其内部状态发生改变时改变其行为能力。
6. 观察者模式(Observer Pattern):
多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。
7. 中介者模式(Mediator pattern):
定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。
8. 迭代器模式(Iterator Pattern):
提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
9. 访问者模式(Visitor Pattern):
在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。
10. 备忘录模式(Memento Pattern):
在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。
11. 解释器模式(Interpreter Pattern):
提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。
一. 模板方法模式定义
设计系统时知道算法所需要的关键步骤,且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知或者说其实现与具体的环境相关,这时可使用模板方法模式,例如去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可在父类中实现,但办理具体事物因人而异如存款取款等可以延迟到子类中实现。
模板模式(Template pattern)
-
在一个上层的抽象类公开定义了执行它的方法的模板,其子类可按需分配重写方法实现,但调用时将以抽象类中的定义方式的进行;
-
模板模式定义一个操作中的算法骨架,而将一些步骤延迟到子类中,使得子类可不改变算法结构就可重定义该算法的某些特定步骤;
-
该类设计模式属于行为型设计模式。
二. 特点
1. 优点
-
算法只存在于父类中,容易修改,需修改算法时,只改父类的模板方法或已实现的某些步骤,子类就会继承这些修改
-
实现了最大化代码复用: 父类的模板方法 和 已实现的某些步骤会被子类继承而直接使用
2. 缺点
-
每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大;
-
父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
-
由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍
三. 应用场景
-
实现一个功能涉及重要、复杂的算法,可以把核心算法设计为模板方法(固定步骤),易变的相关细节功能延迟到子类实现。
-
当需要控制子类扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。
-
一般模板方法都加上final关键字,防止子类重写模板方法 template()//执行算法骨架的方法;
四. 模式的结构
1.模式结构图
2.模板方法角色分析
1>AbstractClass(抽象模板类):负责给出一个算法的轮廓和骨架,它由一个模板方法和若干个基本方法构成,这些方法定义如下:
-
模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法
-
基本方法:是整个算法中的一个步骤,包含以下几个种类:
-
抽象方法:在抽象类中声明,由具体子类实现;
-
具体方法:在抽象类中已实现,在具体子类中可以继承或重写它;
-
钩子方法:在抽象类中可定义一个方法,子类视情况决定是否重写该方法,包括用于判断的逻辑方法和需子类重写的空方法两种;
2>ConcreteClass(具体子类): 实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。
3.模板方法中的钩子方法
1>在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为"钩子";
2>还是用上面做豆浆的例子来讲解,比如我们还希望制作纯豆浆,不添加任何的配料,请使用钩子方法对前面的模板方法进行改造;
五. 模式的实现
编写制作豆浆程序,说明如下:
1)制作豆浆的流程选材 ---> 添加配料 --->浸泡 -->放到豆浆机打碎
2)通过添加不同的配料,可制作出不同口味的豆浆;
3)选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的
4)请使用 模板方法模式 完成
1. 实例结构图
2. 相关代码实现
object TemplateMethodClient {
@JvmStatic
fun main(args: Array<String>) {
println("制作黑豆豆浆")
val blackSoyMilk = BlackSoyMilk()
blackSoyMilk.make()
println("制作花生豆浆")
val peanutSoyMilk = PeanutSoyMilk()
peanutSoyMilk.make()
}
}
//抽象模板类
abstract class SoyBeanMilk {
fun make(){
select()
addCondiments()
soak()
beat()
}
//选原料
private fun select(){
println("第一步, 选择好的新鲜黄豆")
}
//添加不同的配料,抽象方法,由子类具体实现
abstract fun addCondiments()
//浸泡
private fun soak(){
println("第三步,黄豆和配料开始浸泡,需要3小时")
}
//打成豆浆
private fun beat(){
println("第四步, 黄豆和配料放到豆浆机打碎, 产出豆浆")
}
}
class BlackSoyMilk : SoyBeanMilk(){
override fun addCondiments() {
println("加入上好的黑豆")
}
}
class PeanutSoyMilk : SoyBeanMilk(){
override fun addCondiments() {
println("加入上好的花生")
}
}
程序运行结果
制作黑豆豆浆
第一步, 选择好的新鲜黄豆
加入上好的黑豆
第三步,黄豆和配料开始浸泡,需要3小时
第四步, 黄豆和配料放到豆浆机打碎, 产出豆浆
制作花生豆浆
第一步, 选择好的新鲜黄豆
加入上好的花生
第三步,黄豆和配料开始浸泡,需要3小时
第四步, 黄豆和配料放到豆浆机打碎, 产出豆浆