模板方法模式--封装算法

来源:互联网 发布:郑州市儿童编程教育 编辑:程序博客网 时间:2024/06/05 00:20

模板方法模式:在一个方法中定义一个算法的步骤,而将一些步骤延迟到子类中。模板方法使得子类在不改变算法结构的情况下,重新定义算法的某些步骤。

下面用一个例子来详细解释一下。

有些人没有咖啡就活不下去,有些人离不开茶,两者共同的成分是什么?当然是咖啡因了。但,还不只是这样,茶和咖啡的冲泡方式非常相似,不信你瞧瞧:

星巴兹咖啡冲泡法:

(1) 把水煮沸

(2) 用沸水冲泡咖啡

(3) 把咖啡倒进杯子

(4) 加糖和牛奶

星巴兹茶冲泡法:

(1) 把水煮沸

(2) 用沸水浸泡茶叶

(3) 把茶倒进杯子

(4) 加柠檬


那用代码实现就是:

public class Coffee {
void prepareRecipe() {
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}

public void boilWater() {
System.out.println("Boiling water");
}

public void brewCoffeeGrinds() {
System.out.println("Dripping Coffee through filter");
}

public void pourInCup() {
System.out.println("Pouring into cup");
}

public void addSugarAndMilk() {
System.out.println("Adding Sugar and Milk");
}
}

接下来是茶

public class Tea {
void prepareRecipe() {
boilWater();
steepTeaBag();
pourInCup();
addLemon();
}

public void boilWater() {
System.out.println("Boiling water");
}

public void steepTeaBag() {
System.out.println("Steeping the tea");
}

public void addLemon() {
System.out.println("Add lemon");
}

public void pourInCup() {
System.out.println("Pouring into cup");
}
}


我们发现了重复的代码,这是好现象。这表示我们需要清理一下设计了。在这里,既然茶和咖啡师如此的相似,似乎我们应该把共同的部分抽出来,放进一个基类里。

看起来这个咖啡和茶的设计练习是相当的直接,你的第一版设计看起来是这样:

CaffeineBeverage:

prepareRecipe();

boilWater();

pourInCup();


Coffee:

prepareRecipe();

brewCoffeeGrinds();

addSugarAndMilk();


Tea

prepareRecipe();

steepTeaBag();

addLemon();


我们的新设计你 觉得怎么样?是不是觉得忽略了某些其他共同点?咖啡和茶还有什么是相似的?我们先从冲泡法入手

(1) 把水煮沸

(2) 用沸水冲泡咖啡

(3) 把咖啡倒进杯子

(4) 加糖和牛奶

(1)、(3)我们已经抽出来放到基类里了,(2)、(4)并没有被抽出来,但是他们是一样的,只是应用在不同的饮料上。

那么我们有办法将prepareRecipe()也抽象化吗?是的,现在就来看看该怎么做,让我们从每一个子类中逐步抽象prepareRecipe(),我们遇到的第一个问题,就是咖啡使用brewCoffeeGrinds()和addSugarAndMilk()方法,而茶使用的是steepTeaBag()和addLemon()方法。

让我们来思考这一点,浸泡(steep)和冲泡(brew)差异其实不大,所以我们给他一个新的方法名称,比方说brew(),然后不管泡茶还是冲泡咖啡我们都用这个名称。类似的,加糖和牛奶也和加柠檬很相似,都是在饮料中加入调料,让我们也用一个新的方法名称来解决这个问题,就叫做addCondiments()好了。这样一来,新的prepareRecipe()方法看起来就是这样:

void prepareRecipe() {

boilWater();

brew();

pourInCup();

addCondiments();

}

现在我们有了新的prepareRecipe()方法,但是需要让他能够符合代码。要想这么做,我们就先从CaffeineBeverage()超类开始:

public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}

abstract void brew();
abstract void addCondiments();

public void boilWater() {
System.out.println("Boiling water");
}

public void pourInCup() {
System.out.println("Pouring into cup");
}
}

最后我们就需要处理咖啡和茶类了,这两个类现在都是依赖超类来处理冲泡法,所以只需自行处理冲泡和添加调料部分:

public class Tea extends CaffeineBeverage {
public void brew() {
System.out.println("Steeping the tea");
}

public void addCondiments() {
System.out.println("Adding Lemon");
}
}


public class Coffee extends CaffeineBeverage {
public void brew() {
System.out.println("Dripping coffee through filter");
}

public void addCondiments() {
System.out.println("Adding Sugar And Milk");
}
}

基本上,我们刚刚实现的就是模板方法模式。模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。

从上面我们可以看出,模板方法模式的优势就是:

1、可以将代码的复用最大化。

2、算法只存在于一个地方,所以容易修改。

3、这个模板提供了一个框架,可以让其他的咖啡因饮料插进来。

4、CaffeineBeverage类专注在算法本身,而由子类提供完整的实现。


0 0
原创粉丝点击