首页 > 代码库 > 设计模式(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 模板

策略:我定义一个算法家族,并让这些算法可以互换。正因为每一个算法都被封装起来了,所以客户可以轻易地使用不同的算法。

模板:我定义一个算法大钢,而由我的子类定义其中某些步骤可以有不同的实现细节。但是我的算法结构依然维持不变。

模板依赖性高一些,必须依赖超类中算法的实现,因为这是算法的一部分。 

策略不依赖任何,整个算法自己搞定。