JAVA设计模式之模板模式

一、模板模式简介

Template Method模式也叫模板方法模式,是行为模式之一,它把具有特定步骤算法中的某些必要的处理委让给抽象方法,通过子类继承对抽象方法的不同实现改变整个算法的行为。

二、模板模式的结构

在这里插入图片描述

三、模板模式的角色与职责

  • AbstractClass:抽象类的父类
  • ConcreteClass:具体的实现子类
  • templateMethod():模板方法
  • method1()与method2():具体步骤方法

四、模板模式的具体实现

星巴兹咖啡现在有两种饮料,一种是茶,另一种是咖啡,让我们来看看他们的制作过程吧。

1、不使用模板模式

方案设计

在这里插入图片描述

类设计

我们先来看茶类:

// An highlighted block
package design.Template.gys.no;
public class Tea {
 public void prepareRecipe() {
  // TODO Auto-generated method stub
  boilWater();
  steepTeaBag();
  pourInCup();
  addLemon();
 }
 public void boilWater() {
  // TODO Auto-generated method stub
  System.out.println("Boiling water");
 }
 public void steepTeaBag() {
  // TODO Auto-generated method stub
  System.out.println("Steeping the tea");
 }
 public void pourInCup() {
  // TODO Auto-generated method stub
  System.out.println("Pouring into cup");
 }
 public void addLemon() {
  // TODO Auto-generated method stub
  System.out.println("Adding Lemon");
 }
}

再看咖啡的制作方法:

// An highlighted block
package design.Template.gys.no;
public class Coffee {
  public void prepareRecipe() {
   // TODO Auto-generated method stub
   boilWater();
   brewCoffeeGrinds();
   pourInCup();
   addSugerAndMilk();
  }
  public void boilWater() {
   // TODO Auto-generated method stub
   System.out.println("Boiling water");
  }
  public void brewCoffeeGrinds() {
   // TODO Auto-generated method stub
   System.out.println("Ddipping Coffee through filter");
  }
  public void pourInCup() {
   // TODO Auto-generated method stub
   System.out.println("Pouring into cup");
  }
  public void addSugerAndMilk() {
   // TODO Auto-generated method stub
   System.out.println("Adding suger and Milk");
  }
}

非常好,大家都学会了星巴兹咖啡的都有技巧,可以回家自己制作了。让我们看看学习成果:

// An highlighted block
package design.Template.gys.no;
public class Test {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  Tea t=new Tea();
  Coffee c=new Coffee();
  t.prepareRecipe();
  System.out.println("---------------");
  c.prepareRecipe();
 }
}
// An highlighted block
Boiling water
Steeping the tea
Pouring into cup
Adding Lemon
---------------
Boiling water
Ddipping Coffee through filter
Pouring into cup
Adding suger and Milk

我们看到,两个制作方法中含大量重复的代码,Coffee和Tea两个类主导控制了算法,当我们需要改变时,需要修改较多的代码,并且类的阻止不具有弹性,算法的知识和实现分散。
现在要将这些代码抽出并抽象到基类中。

2、使用模板模式

方案设计

在这里插入图片描述

类设计

让我们看一下抽象之后的操作步骤吧。
在基类中,我们定义了两个抽象的方法,子类在继承的时候会选择覆盖,用以实现自己的方式。

// An highlighted block
package design.Template.gys.Template;
public abstract  class Drink {
 public void prepareRecipe() {
  // TODO Auto-generated method stub
  boilWater();
  brew();
  pourInCup();
  addElement();
 }
 public void boilWater() {
  // TODO Auto-generated method stub
  System.out.println("Boiling water");
 }
 public abstract void brew();
 public void pourInCup() {
  // TODO Auto-generated method stub
  System.out.println("Pouring into cup");
 }
 public abstract void addElement();
}

我们来看重新设计之后的饮料类。
茶:

// An highlighted block
package design.Template.gys.Template;
public class Tea extends Drink{
 @Override
 public void brew() {
  // TODO Auto-generated method stub
  System.out.println("Steeping the tea");
 }
 @Override
 public void addElement() {
  // TODO Auto-generated method stub
  System.out.println("Adding Lemon");
 }
}

咖啡:

// An highlighted block
package design.Template.gys.Template;
public class Coffee extends Drink{
 @Override
 public void brew() {
  // TODO Auto-generated method stub
  System.out.println("Ddipping Coffee through filter");
 }
 @Override
 public void addElement() {
  // TODO Auto-generated method stub
  System.out.println("Adding suger and Milk");
 }
}

可以看到,二者在继承的同时实现了自己的两个方法。Drink类知道了一切算法,并且只存在一个地方,修改较容易。Drink提供了一个冲泡算法的框架,让子类饮料实现自己的方法。
框架专注在算法本身,二子类提供完整的实现。
下面我们看一下测试代码:

// An highlighted block
package design.Template.gys.Template;
public class Test {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  Drink t=new Tea();
  Drink c=new Coffee();
  t.prepareRecipe();
  System.out.println("-------------");
  c.prepareRecipe();
 }
}

结果如下:

// An highlighted block
Boiling water
Steeping the tea
Pouring into cup
Adding Lemon
-------------
Boiling water
Ddipping Coffee through filter
Pouring into cup
Adding suger and Milk

可以说很完美了。
接下来我们看模板模式中的另一个工具。

3、钩子

类设计

钩子时在抽象类中的方法,但是只有空的或者默认的实现,钩子的存在让子类有能力对算法的不同点进行挂钩,要不要挂钩看子类。
我们使用钩子对是否加调料进行控制。
同样的先定义抽象类:

// An highlighted block
package design.Template.gys.hook;
public abstract class Drink {
 public void prepareRecipe() {
  // TODO Auto-generated method stub
  boilWater();
  brew();
  pourInCup();
  if(customer())
   addElement();
 }
 public void boilWater() {
  // TODO Auto-generated method stub
  System.out.println("Boiling water");
 }
 public abstract void brew();
 public void pourInCup() {
  // TODO Auto-generated method stub
  System.out.println("Pouring into cup");
 }
 public abstract void addElement();
 public boolean customer() {
  return true;
 }
}

可以看到,抽象类中默认的钩子返回的是true,也就是需要添加调料,现在星巴兹咖啡只在咖啡中添加糖和牛奶,而不在茶中添加柠檬。所以咖啡类中不重新实现钩子,使用默认的实现,但是在茶中我们重写基类的钩子方法,使其不添加柠檬。
咖啡:

// An highlighted block
package design.Template.gys.hook;
public class Coffee extends Drink{
 @Override
 public void brew() {
  // TODO Auto-generated method stub
  System.out.println("Ddipping Coffee through filter");
 }
 @Override
 public void addElement() {
  // TODO Auto-generated method stub
  System.out.println("Adding suger and Milk");
 }
}

茶:

// An highlighted block
package design.Template.gys.hook;
public class Tea extends Drink{
 @Override
 public void brew() {
  // TODO Auto-generated method stub
  System.out.println("Steeping the tea");
 }
 @Override
 public void addElement() {
  // TODO Auto-generated method stub
  System.out.println("Adding Lemon");
 }
 public boolean customer() {
  return false;
 }
}

跳过我们的测试过程,直接看结果:

// An highlighted block
Boiling water
Steeping the tea
Pouring into cup
-------------
Boiling water
Ddipping Coffee through filter
Pouring into cup
Adding suger and Milk

可以看到我们控制了抽象类中的部分算法的实现。也就是说,如果该算法的这个部分是可选的,那么我们就是用钩子来实现。

五、模板模式与策略模式的区别

  • 侧重点不同:模板模式封装的是一个算法的具体步骤,策略模式通过接口将某一方法功能变为一个方法族
  • 模板模式使用的是继承的方式实现,策略模式使用的是组合的方式
    好莱坞原则:别调用我们,我们调用你。可以很好的防止依赖腐败。

要抱抱才会开心呀~~~~~~~~~~~~

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值