模板方法基本介绍

1.模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),
  在一个抽象类公开定义了执行它  的方法的模板。它的子类可以按需要重写方法实现,
  但调用将以抽象类中定义的方式进行。
2.简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,
  使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤

模板方法的原理类图

设计模式之模板模式_子类
对原理类图的说明(模板方法模式的角色及职责)
1.AbstractClass抽象类,类中实现了模板方法,定义了算法的骨架,具体子类需要去实现其他的抽象方法operation2,3,4
2.ConcreteClass实现抽象方法operation2,3,4,以完成算法中特定子类的相关步骤

模板方法模式解决豆浆制作问题

编写制作豆浆的程序,说明如下:
1.制作豆浆的流程(选材-添加配料--浸泡}-放到豆浆机打碎2)通过添加不同的配料,可以制作出不河口味的豆浆
2.选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的4)请使用模板方法模式完成

设计模式之模板模式_模板方法_02

代码实现

package com.cedric.template;

public abstract class SoyaMilk {

    // 模板方法,make,模板方法可以做成final,不让子类去覆盖
    final void make(){
        select();
        addCondiments();
        soak();
        beat();
    }

    // 选材料
    void select(){
        System.out.println("第一步:选择新鲜黄豆");
    }

    // 添加不同的配料,抽象方法,子类具体实现
    abstract void addCondiments();

    // 浸泡
    void soak(){
        System.out.println("第三步,黄豆和配料开始浸泡,需要3小时");
    }

    void beat(){
        System.out.println("第四步:黄豆和配料一起打碎");
    }
}
package com.cedric.template;

public class RedBeanSoyaMike extends SoyaMilk{
    @Override
    void addCondiments() {
        System.out.println("加入挑好的红豆");
    }
}

package com.cedric.template;

public class PeanutSoyaMike extends SoyaMilk{
    @Override
    void addCondiments() {
        System.out.println("加入挑好的花生");
    }
}
package com.cedric.template;

public class Client {
    public static void main(String[] args) {
        // 制作红豆豆浆
        System.out.println("制作红豆豆浆");
        SoyaMilk readBeanSoyaMike = new RedBeanSoyaMike();
        readBeanSoyaMike.make();

        // 制作花生豆浆
        System.out.println("制作花生豆浆");
        SoyaMilk peanutSoyaMike = new RedBeanSoyaMike();
        peanutSoyaMike.make();
    }
}

模板方法模式的钩子方法

在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为"钩子"

使用钩子方法改造豆浆制作

package com.cedric.template.improve;

public abstract class SoyaMilk {

    // 模板方法,make,模板方法可以做成final,不让子类去覆盖
    final void make(){
        select();
        if(customerWantCondiments()){
            addCondiments();
        }
        soak();
        beat();
    }

    // 选材料
    void select(){
        System.out.println("第一步:选择新鲜黄豆");
    }

    // 添加不同的配料,抽象方法,子类具体实现
    abstract void addCondiments();

    // 浸泡
    void soak(){
        System.out.println("第三步,黄豆和配料开始浸泡,需要3小时");
    }

    void beat(){
        System.out.println("第四步:黄豆和配料一起打碎");
    }

    // 钩子方法,决定是否添加配料
    boolean customerWantCondiments(){
        return true;
    }
}
package com.cedric.template.improve;

public class RedBeanSoyaMike extends SoyaMilk {
    @Override
    void addCondiments() {
        System.out.println("加入挑好的红豆");
    }
}

package com.cedric.template.improve;

public class PeanutSoyaMike extends SoyaMilk {
    @Override
    void addCondiments() {
        System.out.println("加入挑好的花生");
    }
}

package com.cedric.template.improve;

public class PureSoyaMike extends SoyaMilk{

    @Override
    void addCondiments() {
        // 空实现
    }

    @Override
    boolean customerWantCondiments() {
        return false;
    }
}
package com.cedric.template.improve;

public class Client {
    public static void main(String[] args) {
        // 制作红豆豆浆
        System.out.println("===========制作红豆豆浆=========");
        SoyaMilk readBeanSoyaMike = new RedBeanSoyaMike();
        readBeanSoyaMike.make();

        // 制作花生豆浆
        System.out.println("==========制作花生豆浆==========");
        SoyaMilk peanutSoyaMike = new RedBeanSoyaMike();
        peanutSoyaMike.make();

        System.out.println("===========制作纯豆浆=========");
        SoyaMilk pureSoyaMike = new PureSoyaMike();
        pureSoyaMike.make();
    }
}

模板方法模式注意事项和细节

1.基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法
  或者已经实现的某些步骤,子类就会继承这些修改
2.实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用
3.既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现
4.该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
5.一般模板方法都加上final关键字,防止子类重写模板方法
6.模板方法使用场景:当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤
  在实现时可能不同,通常考虑用模板方法模式来处理