首页 > 代码库 > 设计模式(8)--模板方法模式
设计模式(8)--模板方法模式
关键词 :hook 钩子 Applet 中 init() destory() 为钩子,需要子类去实现。
新原则: 别调用我们,我们会调用你们 高层调用低层 低层不能调用高层。
目的 :封装算法
模板方法:子类决定如何实现算法中的步骤
策略:封装可互换的行为,然后使用委托来决定要采用哪一个行为
工厂方法:由子类决定实例化哪个具体类
OO原则:新原则上面
OO模式:模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类。模板方法使得子类可以在不改变算法的结构的情况下,重新定义算法中的某些步骤。
abstract class AbstractClass{
<span style="white-space:pre"> </span>final void templateMethod(){
<span style="white-space:pre"> </span> primitiveOperation1(); // 抽象方法
primitiveOperation2();
concreteOperation(); //final 的
hook();
}
<span style="white-space:pre"> </span>abstract void primitiveOperation1(); //这两个方法由具体子类实现 。
<span style="white-space:pre"> </span>abstract void primitiveOperation2();
final void concreteOperation(){
// 这里是实现 //这个具体的方法定义在抽象类中将它声明为final,这样一来子类就无法覆盖它,它可以被模板方法直接使用或被子类使用
}
void hook(){} //钩子 这是一个具体的方法,但它什么事情都不做 称为 hook 子类可以视情况决定要不要覆盖它们。 }
//对模板方法进行挂钩
钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类决定。
public abstract class CaffeineBeverageWithHook{
void PrepareRecipe(){
<span style="white-space:pre"> </span>brew();
pourInCup();
if(<span style="color:#ff6666;">customerWantsCondiments</span>()){ //如果 “ 想要 ”调料, 才添加调料 , 调用的钩子。
addCondiments();
}
}
abstract void brew();
void pourInCup(){
<span style="white-space:pre"> </span>syso.
}
boolean customerWantsCondiments(){ //这就是一个钩子,子类可以覆盖这个方法,但不见得一定要这么做。
<span style="white-space:pre"> </span>return true;
} }钩子可以做为条件控制语句,影响抽象类中的算法流程。
钩子的另一个用法,是让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤作出反应。
新原则和依赖倒置原则:依赖倒置原则教我们尽量避免使用具休类,而多使用抽象类。
新原则是用在创建框架或组件上的一种技巧,好让低层组件能够被挂钩进计算中,而且又不会让高层组件依赖低层组件。两者的目标都是在于解耦。
JavaAPI 中的 模板方法
Arrays.Sort()
Java数组类的设计者提供一个模板方法用来排序。 下面是简化代码
public static void sort(Object[] a){ //此方法只是一个辅助方法,用来创建一个数组的拷贝,然后将其传给mergetSort()方法当作目标数组。
Object aux[] =(Object)a.clone();
mergeSort(aux,a,0,a.length,0); //mergeSort() 方法包含排序算法, 此算法依赖于 compareTo()方法的实现来完成算法。 }
private static void mergeSort(Object src[],Object dest[],int low,int high,int off){ //把这想像成一个模板方法
for(int i =low;i<high;i++){
<span style="white-space:pre"> </span>for(int j=i;j>low && ((Comparable)dest[j-1]).compareTo((Compareable)dest[j])>0;j--){ //我们需要实现compareTo()方法 ,“填补”模板方法
<span style="white-space:pre"> </span>swap(dest,j,j-1); //这是一个具体的方法,已经在数组类中定义了。
}
} return ; }数组无法继承,所以如何使用sort() ?
sort()的设计者希望这个方法能用于所有的数组,所以把sort()变成静态的方法,这样任何数组都能使用这个方法。
因为sort()并不是真正定义在超类中,所以sort()方法需要知道你已经实现了这个compareTo()方法,否则无法进行排序。
所以数组中要排序的对象需要实现 Comparable接口。
例子: 比较鸭子
public class Duck implements Comparable{
int weight; //重量
public int compareTo(Object object){ //此方法需要传入别一只鸭子,和本身这只鸭子做比较
<span style="white-space:pre"> </span>Duck otherDuck = (Duck)object;
if(this.weight<otherDuck.weight){
return -1;
}else if (this.weight==otherDuch.weight){
return 0;
}else{
<span style="white-space:pre"> </span> return 1;
}<span style="white-space:pre"> </span>
} }开始排序
public class DuckSortTest{
public static void main(String args[]){
Duck[] ducks = {
new Duck("daffy",8),
new Duck("dewey",2),
new Duck("Howard",7)
};
<pre name="code" class="html"> display(ducks);
Arrays.sort(ducks); //调用Arrays 的静态方法sort() 把 鸭子数组当用参数传进去
display(ducks);
public stati void disply(Duck[] ducks){
for(int i=0;i<ducks.length;i++){
syso(ducks[i]);
}
}
} }
要点:
(1)“模板方法”定义了算法的步骤,把这些步骤的实现延迟到子类
(2)模板方法模式为我们提供了一种代码复用的重要技巧。
(3)模板方法的抽象类可以定义具体方法,抽象方法和钩子。
(4)抽象方法由子类实现。
(5)钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要去覆盖它。
(6)为了防止子类改变模板方法中的算法,可以将模板方法声明为final
(7)好莱坞原则告诉我们,将决策权放在高层模块中,以便决定如何以及何时调用低层模块。
(8)你将在真实世界代码中看到模板方法模式的许多变体,不要期待它们全都是一眼就可以被你认出的。
(9)策略模式和模板方法模式都封装算法,一个用组合,一个用继承。
(10)工厂方法是模板方法的一种特殊版本。
策略VS 模板
策略:我定义一个算法家族,并让这些算法可以互换。正因为每一个算法都被封装起来了,所以客户可以轻易地使用不同的算法。
模板:我定义一个算法大钢,而由我的子类定义其中某些步骤可以有不同的实现细节。但是我的算法结构依然维持不变。
模板依赖性高一些,必须依赖超类中算法的实现,因为这是算法的一部分。
策略不依赖任何,整个算法自己搞定。