您的位置:首页 > 其它

模板方法模式

2016-03-09 09:22 267 查看
【0】README
0.1)本文部分描述转自 “head first设计模式”,旨在学习 模板方法模式 的基础知识;

【1】看个荔枝——星巴克咖啡
1.1)星巴克咖啡冲泡法steps:

step1)把水煮沸;
step2)用沸水冲泡咖啡;
step3)把咖啡倒进杯子;
step4)加糖和牛奶;

1.2)星巴克茶冲泡法steps:

step1)把水煮沸;

step2)用沸水浸泡茶叶;

step3)把茶倒进杯子;

step4)加柠檬;

2)对以上问题的分析(Analysis)
A0)上述两种泡法都采用了相同的算法:

step1)把水煮沸;

step2)用热水泡咖啡或者茶;

step3)将饮料倒进杯子;

step4)在饮料内加入适当的调料;

A1)我们看到,step2 和 step4 处理的代码是一样的,所以将step2 和 step4 抽取到基类并具体实现,而基类只给出 step1 和 step3  的 抽象定义,由子类去具体实现;
A2)具体荔枝:
package com.designpattern.chapter8;

public abstract class CaffeineBeverage {

final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}

abstract void brew();

abstract void addCondiments();

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

void pourInCup() {
System.out.println("Pouring into cup");
}
}
package com.designpattern.chapter8;

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");
}
}
package com.designpattern.chapter8;

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

3)模板方法:定义了一个算法的steps,并允许子类的一个或多个steps提供实现;
Attention):这里要和我们的论文算法的实现联系起来,特别是对于机器学习的算法,其步骤都是一致的,可以结合模板方法模式来实现;(干货——将模板方法模式应用到机器学习的算法中)
4)钩子(hook): 钩子是一种被声明在抽象类中的方法,但只有空的实现或者默认的实现;(干货——引入钩子)
4.1)钩子的存在: 可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类自行决定;
4.2)使用钩子:我们在子类中覆盖它;
4.3)算法中某个操作是可选的,就用钩子;
package com.designpattern.chapter8;

public abstract class CaffeineBeverageWithHook {

final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}

abstract void brew();

abstract void addCondiments();

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

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

boolean customerWantsCondiments() { // 钩子
return true;
}
}
public class CoffeeWithHook extends CaffeineBeverageWithHook {

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

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

public boolean customerWantsCondiments() { //调用钩子

String answer = getUserInput();

if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
}
}

【2】好莱坞原则
2.1)定义:别调用我们,我们会调用你;
2.2)在好莱坞原则下:我们允许底层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些底层组件。换句话说,高层组件对待底层组件的方式是“别调用我们,我们会调用你”;



2.3)好莱坞原则和模板方法的连接

对上图的分析(Analysis):饮料的客户代码只依赖CaffeineBeverage 抽象,而不依赖于具体的Tea 或 Coffee。这可以减少整个系统的依赖;



【3】用模板方法排序
3.1)还记得 Comparable 和 compareTo() 方法吗?这种比较大小的算法,采用的就是 模板方法模式;(干货——经典荔枝,模板方法模式应用于Arrays.sort
排序)

3.2)看个荔枝(Arrays.sort):
package com.designpattern.chapter8;

public class Duck implements Comparable<Duck>{

String name;
int weight;

public Duck(String name, int weight) {
this.name = name;
this.weight = weight;
}

@Override
public int compareTo(Duck o) {
if(this.weight > o.weight)
return -1;
else if(this.weight == o.weight)
return 0;
else
return 1;
}

@Override
public String toString() {
return "name: " + name + "weight: " + weight;
}
}
package com.designpattern.chapter8;

import java.util.Arrays;

public class MyTest {

public static void main(String[] args) {
Duck[] ducks = {
new Duck("nihao9",9),
new Duck("nihao10",10),
new Duck("nihao8",8)
};
Arrays.sort(ducks);
for (Duck duck : ducks) {
System.out.println(duck);
}
}
}

对Arrays.sort方法的分析(Analysis):

A1)sort的设计者希望这个方法能应用于所有的数组,所以他们把sort()变成是静态的方法,这样一来,任何数组都可以使用这个方法。但是没有关系,他使用起来和它被定义在超类中是一样的。现在,还有一个细节要告诉你:因为 sort()并不是真正定义在超类中,所以sort方法需要知道你已经实现了这个compareTo()方法就可以了,否则就无法进行排序。
A2)方法调用轨迹:MyTest.main() -> Arrays.sort() -> ComparableTimSort.sort() -> ComparableTimSort.binarySort()
-> Comparable.compareTo()

【4】模板方法模式总述: 模板方法模式——在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些steps;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: