抽象是面向对象编程的核心思想,从某种角度来看,抽象,就是把可变的部分和不可变部分分离开来,今天介绍的模板方法模式,体现的就是这样一种思想。总结起来,模板方法模式可以用一句话来概括:以不变应万变。


1.模板方法模式

模板方法模式(Template Method Pattern),定义了一个算法的骨架,将一些具体步骤的实现推迟到子类中。

模板方法设计模式的核心思想就是将“可变部分”与“不可变部分”分离,通常,在一个抽象基类中定义模板方法,该方法即算法不可变部分,其中调用了一系列抽象方法,这些可重写的抽象方法即可变部分,由其子类重写。因此,模板方法模式可以在不改变算法结构的情况下,重新调整算法中的某些步骤。

模版方法模式的UML类图:

java 一个功能模块软件设计包括哪些框图 java模块设计思想_设计模式

图中,

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.总结

这里再强调一遍,用一句话概括模版方法模式就是:以不变应万变。这其中体现出的是面向对象编程当中最基本和最重要的思想:抽象。模版方法模式通过分离可变部分和不可变部分,实现了代码的解耦,使扩展和维护更加方便,模版方法模式在实际开发中大量应用,尽管很多时候是无意的。我想之所以要学习程序设计模式,并不是为了死记硬背其流程和步骤,应该体会一下各个模式背后的思想精髓,才能对编程这件事情有更加深刻的理解。