一 前言
在面向对象开发过程中,通常会遇到这样的一个问题,我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序,但是,某些步骤的具体实现是未知的,或者说某些步骤的实现是会随着环境的变化而改变,这类问题的解决方案就是我们要讲的模板方法模式。
二 定义
定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
三 使用场景
- 多个子类有共有的方法,并且逻辑基本相同时。
- 重要&复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
四 UML类图
- AbsTemplate:抽象类,定义一个算法框架
- ConcreteImplA:具体实现类A
- ConcreteImplB:具体实现类B
五 代码示例
模板方法实际上是封装一个固定流程,就像是一套执行模板一样,第一步该做什么,第二步该做什么都已经在抽象类中定义好。而子类可以有不同的算法实现,在框架不被修改的情况下实现某些步骤的算法替换,下面以打开计算机这个动作来简单演示一下模板方法。打开计算机的整个过程都是相对固定的,首先启动计算机电源,计算机检测自身状态没有问题时将进入操作系统,对用户进行验证之后即可登录计算机,下面我们使用模板方法来模拟一下这个过程:
5.1 定义一个抽象的算法流程
abstract class AbstractComputer {
var TAG = "AbstractComputer"
open fun powerOn(){
Log.d(TAG,"开启电源")
}
open fun checkHardware(){
Log.d(TAG,"硬件检查")
}
open fun loadOS(){
Log.d(TAG,"载入操作系统")
}
open fun login(){
Log.d(TAG,"小白的计算机无验证,直接进入系统")
}
final fun startUp(){
Log.d(TAG,"------ 开机 START ------")
powerOn();
checkHardware();
loadOS();
login();
Log.d(TAG,"------ 关机 END ------")
}
}
5.2 程序员的计算机
class CoderComputer : AbstractComputer(){
override fun login() {
Log.d(TAG,"程序员只需要进行用户和密码验证就可以了")
}
}
5.3 军用计算机
class MilitaryComputer : AbstractComputer() {
override fun checkHardware() {
super.checkHardware()
Log.d(TAG,"检查硬件防火墙")
}
override fun login() {
Log.d(TAG,"进行指纹识别等复杂的用户验证")
}
}
5.4 测试代码
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val coderComputer = CoderComputer()
val militaryComputer = MilitaryComputer()
coderComputer.startUp()
militaryComputer.startUp()
}
---------------------------------------------------------------------------
结果:
D/AbstractComputer: ------ 开机 START ------
D/AbstractComputer: 开启电源
D/AbstractComputer: 硬件检查
D/AbstractComputer: 载入操作系统
D/AbstractComputer: 程序员只需要进行用户和密码验证就可以了
D/AbstractComputer: ------ 关机 END ------
D/AbstractComputer: ------ 开机 START ------
D/AbstractComputer: 开启电源
D/AbstractComputer: 硬件检查
D/AbstractComputer: 检查硬件防火墙
D/AbstractComputer: 载入操作系统
D/AbstractComputer: 进行指纹识别等复杂的用户验证
D/AbstractComputer: ------ 关机 END ------
六 优点和缺点
优点:
- 封装不变的部分,拓展可变的部分
- 提取公共代码,便于维护
缺点:
模板设计模式会使代码的可读性变差
七 Android源码上的运用
- Activity的生命周期方法
- AsyncTask四个常用的方法