模板模式和 策略模式使用場景相似,都是把算法進行封裝,能夠用分離高層算法和低層的具體實現細節。都容許高層算法獨立於他的具體實現細節的重用。可是實現方式不一樣,在實現方式上,模板模式使用的是繼承,策略模式則使用的委託。html
模板模式比較老,缺點是具體的實現和通用的算法緊密的耦合在了一塊兒,這樣的話具體的一個實現只能被一個算法操縱。父類的的信息更多的暴露給子類。java
而策略模式是委託的經典用法。策略模式消除了通用的一個算法和具體實現的耦合,使得具體的實現能夠被多個通用的算法操縱。可是策略模式一樣的,增長了類的層次和額外的複雜性,之內存和運行時間開銷做爲代價。算法
模板模式的UML靜態圖
spring
模板模式展現了面向對象編程中諸多經典重用形式的一種。其中,通用算法被放置在基類中,而且經過繼承在不一樣的具體上下文中實現該通用算法。編程
例如spring 中 AbstractApplicationContext類中的getBeanFactory方法和refreshBeanFactory方法,在本類中僅僅對這兩個方法作了定義,並在obtainFreshBeanFactory()方法中進行了調用,可是這兩個方法的實現並無在本類中,而是在其子類AbstractRefreshableApplicationContext中進行了具體的實現。可是這項技術是有代價的,繼承是一種很是強的關係。派生類不可避免的要和他們的基類捆綁在一塊兒。數組
接下來用一個示例來演示模板模式的用法:app
public abstract class Application { protected abstract void init(); protected abstract void idle(); protected abstract void cleanup(); private boolean isDone = false; protected void setDone(){ isDone = true; } protected boolean done (){ return isDone; } /** * 模板模式,把須要執行的方法封裝到抽象方法中 */ public void run(){ init(); while(!done()){ idle();; } cleanup(); } }
父類把子類須要實現的方法做爲抽象方法,而後把通用的算法進行封裝,封裝到了run方法中ide
/** * Created by wangtf on 2015/11/19. * 模板模式 */ public class FtocTemplateMethod extends Application{ private InputStreamReader in; private BufferedReader br; @Override protected void init() { in = new InputStreamReader(System.in); br = new BufferedReader(in); } public static void main(String[] args) { (new FtocTemplateMethod()).run(); } @Override protected void idle() { String fahrString = readLineAndReturnNullIfError(); if(fahrString ==null ||fahrString.length()==0){ setDone(); }else { System.out.println("to do something:" + fahrString); } } @Override protected void cleanup() { System.out.print("ftoc exit!"); } private String readLineAndReturnNullIfError(){ String s ; try{ s = br.readLine(); }catch (IOException e){ s = null; } return s; } }
子類繼承父類,實現父類中的抽象方法,具體的算法被封裝到了父類中。this
策略模式的UML靜態圖spa
策略模式使用了一種很是不一樣的方法類倒置通用算法和具體實現之間的依賴關係
用示例演示策略模式:
/** * Created by wangtf on 2015/11/19. */ public interface Application { public void init(); public void idle(); public void cleanUp(); public boolean done(); }
定義接口
/** * 策略模式 * Created by wangtf on 2015/11/19. */ public class FtosStrategy implements Application{ private InputStreamReader in; private BufferedReader br; private boolean isDone = false; @Override public void init() { in = new InputStreamReader(System.in); br = new BufferedReader(in); } @Override public void idle() { String fahrString = readLineAndReturnNullIfError(); if(fahrString ==null ||fahrString.length()==0){ setDone(); }else { System.out.println("to do something:" + fahrString); } } @Override public void cleanUp() { System.out.print("ftoc exit!"); } protected void setDone(){ isDone = true; } @Override public boolean done() { return isDone; } private String readLineAndReturnNullIfError(){ String s ; try{ s = br.readLine(); }catch (IOException e){ s = null; } return s; } }
實現接口中的內容
/** * Created by wangtf on 2015/11/19. */ public class ApplicationRunner { private Application app ; ApplicationRunner(Application app){ this.app = app; } public void run(){ app.init(); while(!app.done()){ app.idle(); } app.cleanUp(); } }
ApplicationRunner中封裝算法(Run方法),這樣算法和具體的對象得以脫離。
實際上一個更恰當的例子是一個排序的例子,例如一個冒泡排序,一般有如下步驟
一、遍歷數組(排序算法)
二、比較兩個數字的大小
三、交換兩個數字的位置
這樣若是直接寫的話,比較兩個數字大小和交換數字的位置將會直接依賴於排序算法,這樣的話咱們只能排序數字,這樣的話就不能把算法脫離開。解決方案是,把2 和3步驟進行抽取,算法獨立,抽取出來之後,咱們不光能比較兩個數字,一樣的能比較對象,比較字符串等等一切咱們想要排序東西。這樣就能夠達到了算法複用的效果。