案例

编写制作豆浆的程序,说明如下:

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

模板模式

模板方法模式(Template Method Pattern)在实现一个抽象类公开定义了执行它的方法的模板,它的子类可以按需重写方法实现,但是调用将以抽象类方式进行。

image.png

AbstractClass 抽象类,类中实现了模板方法,定义了算法骨架,具体子类需要去实现其他抽象方法

ConcreateClass 实现了抽象方法operation2,3,4,完成算法中特定子类的步骤

豆浆制作

image.png

  1. //抽象类,表示豆浆
  2. public abstract class SoyaMilk {
  3. //模板方法, make , 模板方法可以做成final , 不让子类去覆盖.
  4. final void make() {
  5. select();
  6. addCondiments();
  7. soak();
  8. beat();
  9. }
  10. //选材料
  11. void select() {
  12. System.out.println("第一步:选择好的新鲜黄豆 ");
  13. }
  14. //添加不同的配料, 抽象方法, 子类具体实现
  15. abstract void addCondiments();
  16. //浸泡
  17. void soak() {
  18. System.out.println("第三步, 黄豆和配料开始浸泡, 需要3小时 ");
  19. }
  20. void beat() {
  21. System.out.println("第四步:黄豆和配料放到豆浆机去打碎 ");
  22. }
  23. }
  1. public class RedBeanSoyaMilk extends SoyaMilk {
  2. @Override
  3. void addCondiments() {
  4. // TODO Auto-generated method stub
  5. System.out.println(" 加入上好的红豆 ");
  6. }
  7. }
  8. public class PeanutSoyaMilk extends SoyaMilk {
  9. @Override
  10. void addCondiments() {
  11. // TODO Auto-generated method stub
  12. System.out.println(" 加入上好的花生 ");
  13. }
  14. }
  1. public static void main(String[] args) {
  2. // TODO Auto-generated method stub
  3. //制作红豆豆浆
  4. System.out.println("----制作红豆豆浆----");
  5. SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
  6. redBeanSoyaMilk.make();
  7. System.out.println("----制作花生豆浆----");
  8. SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
  9. peanutSoyaMilk.make();
  10. }

模板模式-钩子方法

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

  1. //抽象类,表示豆浆
  2. public abstract class SoyaMilk {
  3. //模板方法, make , 模板方法可以做成final , 不让子类去覆盖.
  4. final void make() {
  5. select();
  6. if(customerWantCondiments()) {
  7. addCondiments();
  8. }
  9. soak();
  10. beat();
  11. }
  12. //选材料
  13. void select() {
  14. System.out.println("第一步:选择好的新鲜黄豆 ");
  15. }
  16. //添加不同的配料, 抽象方法, 子类具体实现
  17. abstract void addCondiments();
  18. //浸泡
  19. void soak() {
  20. System.out.println("第三步, 黄豆和配料开始浸泡, 需要3小时 ");
  21. }
  22. void beat() {
  23. System.out.println("第四步:黄豆和配料放到豆浆机去打碎 ");
  24. }
  25. //钩子方法,决定是否需要添加配料
  26. boolean customerWantCondiments() {
  27. return true;
  28. }
  29. }
public class PureSoyaMilk extends SoyaMilk{

    @Override
    void addCondiments() {
        // TODO Auto-generated method stub
        //空实现
    }

    @Override
    boolean customerWantCondiments() {
        // TODO Auto-generated method stub
        return false;
    }

}

注意

基本是思想是:算法值存在于一个地方,也就是在父类中,容易修改。
实现了最大代码复用:父类的模板方法和已实现的某些步骤会被子类继承而直接使用
既统一了算法,也提供了很大灵活性。:父类的模板方法确保了算法的结构保存不变,同时由子类提供部分步骤的实现

不足之处:
每一个不用的实现都需要一个子类实现
一般模板方法上都加final关键字,防止子类重写模板方法

使用场景: 当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但是个别步骤在实现时可能不同,通常考虑使用模板方法来处理**