模板方法模式

当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理 。
模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
--《大话设计模式》
特点:
    该模式通常用以提炼重复代码到父类中,而不是让每个子类都去重复。
    模板方法模式就是提供了一个很好的代码复用平台。
    当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。
 
模板方法模式中的方法:
    分为两大类:模板方法和基本方法
    模板方法
            定义在抽象类中,把基本方法组合在一起形成一个总算法或总行为的方法。
             一个抽象类中可以有任一多个模板方法,而不限于一个。每个模板方法可以调用任一多个具体方法。
 
    基本方法
            分为三种:抽象方法(Abdstract Method) 具体方法(Contrete Method) 钩子方法(Hock Method)
  • 抽象方法:在抽象类中声明,由具体子类实现。abstract 关键字修饰
  • 具体方法:在抽象类中声明并实现,而子类并不实现和置换。
  • 钩子方法:在抽象类中声明并实现,而子类加以扩展。通常抽象类给出的是一个空实现。 
    
模板方法模式骨架
public abstract class AbstractTemplate {
    /**
     * 模板方法
     */
    public void templateMethod(){
        //调用基本方法
        abstractMethod();
        hookMethod();
        concreteMethod();
    }
    /**
     * 基本方法的声明(由子类实现)
     */
    protected abstract void abstractMethod();
    /**
     * 基本方法(空方法)
     */
    protected void hookMethod(){}
    /**
     * 基本方法(已经实现)
     */
    private final void concreteMethod(){
        //业务相关的代码
    }
}
总的来说,模板方法模式就是通过抽象类来定义一个逻辑模板、框架、原型,然后将无法决定的部分抽象成抽象类方法交由子类来实现,一般这些抽象类的调用逻辑仍然在抽象类中完成。因此,模板就是定义一个框架,比如盖房子,我们定义一个模板,房子要封闭,有门,有窗等等,但是要什么样的门,什么样的窗,这些并不在模板中描述,交由子类来完善,例如门使用防盗门,窗使用北向的窗等等。
 
接下来,用实际代码来模拟如何使用模板方法模式建造房屋。
首先,我们构建建造房屋的抽象类:
package template;
/**
*
* Title: HouseTemplate Description: 房子抽象类 (模板模式)
*
* @author yacong_liu Email:2682505646@qq.com
* @date 2019年1月12日
*/
public abstract class HouseTemplate {
    protected String name;
    protected HouseTemplate(String name) {
        this.name = name;
    }
    /*
     * 基本方法-留给子类实现
     */
    protected abstract void buildDoor();
    /*
     * 基本方法-留给子类实现
     */
    protected abstract void buildWindow();
    /*
     * 基本方法-留给子类实现
     */
    protected abstract void buildWall();
    /*
     * 基本方法-留给子类实现
     */
    protected abstract void buildBase();
    /*
     * 基本方法-留给子类实现
     */
    protected abstract void buildToliet();
    /*
     * 钩子方法
     */
    protected boolean isBuildToliet() {
        return false;
    }
    /*
     * 模板方法
     */
    public final void buildHourse() {
        buildBase();
        buildWall();
        buildDoor();
        buildWindow();
        if (isBuildToliet()) {
            buildToliet();
        }
    }
}

其次,构建建造房屋A和B的具体实现类:

package template;
/**
*
* Title: HouseA
* Description: 建造A房屋
* @author yacong_liu Email:2682505646@qq.com
* @date 2019年1月12日
*/
public class HouseA extends HouseTemplate {
    private boolean isBuildToliet;
    protected HouseA(String name) {
        super(name);
    }
    protected HouseA(String name, boolean isBuildToliet) {
        super(name);
        this.isBuildToliet = isBuildToliet;
    }
    @Override
    protected void buildDoor() {
        System.out.println(name + " 的门采用防盗门");
    }
    @Override
    protected void buildWindow() {
        System.out.println(name + "的窗户要面向北方");
    }
    @Override
    protected void buildWall() {
        System.out.println(name + "的墙使用大理石建造");
    }
    @Override
    protected void buildBase() {
        System.out.println(name + "的地基使用钢铁地基");
    }
    @Override
    protected void buildToliet() {
        System.out.println(name + "的厕所建在东南角");
    }
    @Override
    protected boolean isBuildToliet() {
        return isBuildToliet;
    }
}
package template;
/**
*
* Title: HouseB
* Description: 建造B房屋
* @author yacong_liu Email:2682505646@qq.com
* @date 2019年1月12日
*/
public class HouseB extends HouseTemplate {
    protected HouseB(String name) {
        super(name);
    }
    @Override
    protected void buildDoor() {
        System.out.println(name + "的门采用木门");
    }
    @Override
    protected void buildWindow() {
        System.out.println(name + "的窗户要向南");
    }
    @Override
    protected void buildWall() {
        System.out.println(name + "的墙使用玻璃制造");
    }
    @Override
    protected void buildBase() {
        System.out.println(name + "的地基使用花岗岩");
    }
    @Override
    protected void buildToliet() {
        System.out.println(name + "的厕所建在西北角");
    }
}

客户端测试类:

package template;

import static org.junit.Assert.*;

import org.junit.Test;

public class HouseTemplateTest {

    @Test
    public void testBuildHourse() {
        HouseTemplate houseA = new HouseA("HouseA", true);
        HouseTemplate houseB = new HouseB("HouseB");

        houseA.buildHourse();
        System.out.println("*************************");
        houseB.buildHourse();

    }

}

输出结果:

HouseA的地基使用钢铁地基HouseA的墙使用大理石建造HouseA 的门采用防盗门HouseA的窗户要面向北方HouseA的厕所建在东南角*************************HouseB的地基使用花岗岩HouseB的墙使用玻璃制造HouseB的门采用木门HouseB的窗户要向南
原文地址:https://www.cnblogs.com/lyc-smile/p/10310425.html