抽象是面向对象编程的核心思想,从某种角度来看,抽象,就是把可变的部分和不可变部分分离开来,今天介绍的模板方法模式,体现的就是这样一种思想。总结起来,模板方法模式可以用一句话来概括:以不变应万变。
1.模板方法模式
模板方法模式(Template Method Pattern),定义了一个算法的骨架,将一些具体步骤的实现推迟到子类中。
模板方法设计模式的核心思想就是将“可变部分”与“不可变部分”分离,通常,在一个抽象基类中定义模板方法,该方法即算法不可变部分,其中调用了一系列抽象方法,这些可重写的抽象方法即可变部分,由其子类重写。因此,模板方法模式可以在不改变算法结构的情况下,重新调整算法中的某些步骤。
模版方法模式的UML类图:
图中,
templateMethod() 模板方法
action1,action2 是需要子类重写的抽象方法
2.代码实现
假设汽车由一条生产线装备(现实中是多条生产线),这条生产线上有各个机器人,入负责底盘的机器人,负责装配发动机的机器人,负责装配轮胎的机器人,负责装配车身的机器人。很显然,机器人可以抽象出一个类代表机器人这个抽象体,每个具体机器人都负责装配某部件。那么,可以在抽象机器人类中,定义一个模版方法,该方法定义了所有机器人装配零件时的通用步骤(算法),而具体细节由各个机器人实现。
首先,定义Car类,即汽车,我们的装配对象。 用布尔类型的属性记录是否已装配了相应零件的状态。
/**
* 汽车类,装配对象
*/
class Car {
private static int count = 0;
private final int id;
public Car() {
id = count++;
}
/** 汽车底盘 */
private boolean chassis = false;
/** 发动机*/
private boolean engine = false;
/** 轮胎 */
private boolean wheels = false;
/** 车身 */
private boolean body = false;
/** 安装底盘*/
public void setChassis(){
chassis = true;
}
/** 安装发动机*/
public void setEngine(){
engine = true;
}
/** 安装轮胎*/
public void setWheels() {
wheels = true;
}
/** 安装车身 */
public void setBody() {
body = true;
}
public String toString() {
return "car" + id + "( chassis:" + chassis + ", engine:" + engine +
", wheels:" + wheels + ", body:" + body + ")" ;
}
}
定义机器人抽象类,有成员属性Assembler,即装配线的引用,该装配线与本例中的模版方法模式无关。定义了模版方法:assemble(),即装配,该方法中设计了一些具体机器人的共通逻辑,而调用的performance(0,则将具体装配推迟到了子类中。
/**
* 机器人抽象类,提供模板方法assemble,以及一系列抽象方法
*/
abstract class Robot {
protected Assembler assembler;
public void setAssembler(Assembler assembler) {
this.assembler = assembler;
}
/** 模板方法 */
protected void assemble() {
System.out.println("开始装配:" + assembler.car);
performance();
System.out.println("装配完成:" + assembler.car);
}
protected abstract void performance();
}
各个具体机器人,实现了“可变”的方法performance()
/**
* 底盘装配机器人
*/
class ChassisRobot extends Robot{
@Override
protected void performance() {
assembler.car.setChassis();
}
}
/**
* 发动机装配机器人
*/
class EngineRobot extends Robot {
@Override
protected void performance() {
assembler.car.setEngine();
}
}
/**
* 轮胎装配机器人
*/
class WheelsRobot extends Robot {
@Override
protected void performance() {
assembler.car.setWheels();
}
}
/**
* 车身装配机器人
*/
class BodyRobot extends Robot {
@Override
protected void performance() {
assembler.car.setBody();
}
}
Assembler,为了更好地完成调度和管理
/**
* 生产线,调度机器人装配
*/
class Assembler {
List<Robot> robots;
Car car;
public Assembler(Car car) {
this.car= car;
//注册机器人
robots = new ArrayList<>();
robots.add(new ChassisRobot());
robots.add(new EngineRobot());
robots.add(new WheelsRobot());
robots.add(new BodyRobot());
}
public void run() {
for (Robot robot : robots) {
robot.setAssembler(this);
robot.assemble();
}
}
}
客户端调用,首先创建Car实体,将其传入生产线Assembler,生产线run起来,即开始装配汽车零件。
public class TemplateDemo {
public static void main(String[] args) {
Car car = new Car();
Assembler assembler = new Assembler(car);
assembler.run();
}
}
输出结果:
开始装配:car0( chassis:false, engine:false, wheels:false, body:false)
装配完成:car0( chassis:true, engine:false, wheels:false, body:false)
开始装配:car0( chassis:true, engine:false, wheels:false, body:false)
装配完成:car0( chassis:true, engine:true, wheels:false, body:false)
开始装配:car0( chassis:true, engine:true, wheels:false, body:false)
装配完成:car0( chassis:true, engine:true, wheels:true, body:false)
开始装配:car0( chassis:true, engine:true, wheels:true, body:false)
装配完成:car0( chassis:true, engine:true, wheels:true, body:true)
3.总结
这里再强调一遍,用一句话概括模版方法模式就是:以不变应万变。这其中体现出的是面向对象编程当中最基本和最重要的思想:抽象。模版方法模式通过分离可变部分和不可变部分,实现了代码的解耦,使扩展和维护更加方便,模版方法模式在实际开发中大量应用,尽管很多时候是无意的。我想之所以要学习程序设计模式,并不是为了死记硬背其流程和步骤,应该体会一下各个模式背后的思想精髓,才能对编程这件事情有更加深刻的理解。