參考資料:
1. head first 設計模式
2. http://blog.csdn.net/hguisu/article/details/7558249/
在看設計模式的時候,總覺得好多設計模式都差不多,容易弄混,因此做點記錄。
一、模板方法
模板方法模式在一個方法中定義了一個算法的步驟(骨架),而將一些步驟延遲到子類中。模板方法使得子類在不改變算法結構的情況下,重新定義算法中的某些步驟。模板方法模式的一般結構如下圖所示:
注:圖片來自Head First 設計模式中文版截圖
可以看到模板方法模式一般是針對一個算法的各個步驟進行操作,算法的步驟由超類AbstractClass控制,子類ConcreteClass只是實現了父類算法的某幾個步驟,本身並不控制算法流程(這點要與下面的策略模式區分)。模板方法模式有幾個好處:
- 算法流程只由超類AbstractClass控制,子類無法去修改算法流程(比如算法的執行順序等,不過可以通過在父類中加入像“鉤子”的方法實際上是可以修改算法流程),但是可以修改算法中的某個步驟細節。這樣要修改算法比較容易,同時也保護了算法(畢竟只由AbstractClass一個類控制)
- 算法中通用的步驟可以放在超類中實現,利用繼承實現了代碼複用
舉個可能比較牽強的例子,比如我在北京,要回到江西去,有一種路線是:北京->武漢->江西,那麼這裏 北京->武漢->江西 這個路線流程就是從北京去往江西的一個算法,這個算法分成了兩個步驟:北京->武漢,武漢->江西,假設北京到武漢只有高鐵,那我只能坐高鐵了,但是從武漢到江西既有高鐵又有硬座,於是我們設計的代碼結構如下:
/**
* 從北京到江西路線算法框架類,確定了整體框架,其中某些步驟需要子類具體實現
* */
public abstract class AbstractFromBeijingToJiangXi {
/**
* 算法框架,定義成final,避免子類去修改算法框架
* */
public final void fromBeijingToJiangXi(){
fromBeijingToWuHan();
fromWuhanToJiangXi();
}
/**
* 這個是算法步驟中變化的步驟,不同的子類有不同的實現
* */
public abstract void fromWuhanToJiangXi();
/**
* 這個是算法的通用步驟,子類不需要實現
* */
public final void fromBeijingToWuHan(){
System.out.println("坐高鐵從:北京 -> 武漢");
}
}
以下是兩個子類的實現:
/**
* 坐高鐵
* */
public class CRHFromBeijingToJiangXi extends AbstractFromBeijingToJiangXi{
/**
* 子類重寫的步驟
* */
@Override
public void fromWuhanToJiangXi() {
System.out.println("坐高鐵從:武漢 -> 江西 ");
}
}
/**
* 做普通硬座
* */
public class NormalFromBeijingToJiangXi extends AbstractFromBeijingToJiangXi {
@Override
public void fromWuhanToJiangXi() {
System.out.println("坐硬座從:武漢-> 江西 ");
}
}
我們這樣使用:
public class Client {
public static void main(String[] args) {
//AbstractFromBeijingToJiangXi road=new CRHFromBeijingToJiangXi();
AbstractFromBeijingToJiangXi road=new NormalFromBeijingToJiangXi();
road.fromBeijingToJiangXi();
}
}
二、策略模式
策略模式定義了算法族,分別封裝起來,讓它們之間可以相互替換,此模式讓算法的變化獨立於使用算法的客戶。還是以上面的例子爲例,從北京到江西,可以有多種交通方案(每種交通方案相當於一個算法)。得到如下的代碼結構:
/**
* 算法族的公共接口
* */
public interface IFromBeijingToJiangXi {
/**
* 不同的算法有不同的實現,子類完全控制算法的步驟流程
* */
public void fromBeijingToJiangXi();
}
子類完全自己實現算法
/**
* 坐高鐵
* */
public class CRHFromBeijingToJiangXi implements IFromBeijingToJiangXi{
/**
* 子類自己完全實現算法的流程
* */
@Override
public void fromBeijingToJiangXi() {
fromBeijingToWuHan();
fromWuhanToJiangXi();
}
public void fromBeijingToWuHan(){
System.out.println("坐高鐵從:北京-> 武漢 ");
}
public void fromWuhanToJiangXi(){
System.out.println("坐高鐵從:武漢->江西 ");
}
}
/**
* 做普通硬座
* */
public class NormalFromBeijingToJiangXi implements IFromBeijingToJiangXi {
/**
* 子類自己完全實現算法的流程
* */
@Override
public void fromBeijingToJiangXi() {
fromBeijingToWuHan();
fromWuhanToJiangXi();
}
public void fromBeijingToWuHan(){
System.out.println("坐硬座從:北京-> 武漢 ");
}
public void fromWuhanToJiangXi(){
System.out.println("坐硬座從:武漢->江西 ");
}
}
如何使用:
public class Client {
private IFromBeijingToJiangXi fromBeijingToJiangXi;
public Client(IFromBeijingToJiangXi fromBeijingToJiangXi){
this.fromBeijingToJiangXi=fromBeijingToJiangXi;
}
public void travel(){
fromBeijingToJiangXi.fromBeijingToJiangXi();
}
public static void main(String[] args) {
//客戶端使用時需要事先知道對應的具體的算法
IFromBeijingToJiangXi fromBeijingToJiangXi=new CRHFromBeijingToJiangXi();
//可以換不同的算法
//IFromBeijingToJiangXi fromBeijingToJiangXi=new NormalFromBeijingToJiangXi();
Client client=new Client(fromBeijingToJiangXi);
client.travel();
}
}
三、 二者的區別
1. 二者針對的對象的粒度不同,給我感覺模板方法模式是以算法的步驟爲單位,而策略模式是以算法爲單位
2. 模板方法模式的子類只修改了算法的某些步驟,並不會去改變算法的框架流程,而策略模式的子類則自己完全定義了算法的步驟和流程