這篇文章主要為大家詳細介紹了java設計模式之模板方法模式的相關資料,具有一定的參考價值,有興趣的小夥伴們可以參考一下
#一、什麼是模板方法模式
概念:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類別中。模板方法使得子類別可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。
通俗的講,模板方法模式是透過把不變行為搬到超類,去除子類別裡面的重複程式碼提現它的優勢,它提供了一個很好的程式碼復用平台。當不可變和可變的方法在子類別中混合在一起的時候,不變的方法就會在子類別中多次出現,這樣如果摸個方法需要修改則需要修改很多個,雖然這個這個問題在設計之初應該想好。這時候模板方法模式就起到了作用了,透過模板方法模式把這些重複出現的方法搬到單一的地方,這樣就可以幫助子類別擺脫重複不變的糾纏。
舉個好懂的例子,小時候筆者家裡窮,在農村上小學的時候考試都是每個學生手抄試卷,因為那個時候學校還沒有試卷印刷。全班五十多個學生每個學生都要重複抄一遍黑板的試卷,並且像筆者這樣的近視眼很容易就抄錯了,8抄成3,7抄成1等到,然後明明做對了但是分數就是不高,導致筆者一直是全班倒數。這就是個很嚴重的重複不可變的問題,現在條件好了不少,學生不需要抄試卷,考卷印刷就解決了這個重複抄試卷的問題。模板方法也是類似。
二、模式對比
1、抄試卷模式
筆者就以抄試卷模式為名來闡述重複不變帶來的不便,以下會對該模式進行改進。
學生甲抄的考卷
public class TestPaperA { //试卷第一题 public void testQuestion1(){ System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈"); System.out.println("答案:C"); } //试卷第二题 public void testQuestion2(){ System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛"); System.out.println("答案:C"); } //试卷第三题 public void testQuestion3(){ System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴"); System.out.println("答案:B"); } }
學生乙抄的考卷
public class TestPaperB { //试卷第一题 public void testQuestion1(){ System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈"); System.out.println("答案:A"); } //试卷第二题 public void testQuestion2(){ System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛"); System.out.println("答案:C"); } //试卷第三题 public void testQuestion3(){ System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴"); System.out.println("答案:D"); } }
客戶端程式碼
public class ShowAnswer { public static void main(String[] args) { System.out.println("学生甲的试卷"); TestPaperA stuA = new TestPaperA(); stuA.testQuestion1(); stuA.testQuestion2(); stuA.testQuestion3(); System.out.println("学生乙的试卷"); TestPaperB stuB = new TestPaperB(); stuB.testQuestion1(); stuB.testQuestion2(); stuB.testQuestion3(); } }
很容易發現上面兩個學生抄的考卷有很多重複的地方,例如試卷的題目,輸出答案的方法,這些都在每個學生試卷類中混合在一起了,既不利於維護,也不利於瀏覽,下面看一下模板方法模式是怎麼改進的。
2、模板方法模式
將每個學生試卷的重複部分提取出來,題目,作答等等。
首先改造試卷類,將該類改為抽象類,在該類中我添加了三個抽象的方法用於子類實現,學生都是要作答的,但是答案不一樣,所以可以將作答的過程作為重複不變的方法提取出來,程式碼如下。
public abstract class TestPaper { //试卷第一题 public void testQuestion1(){ System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈"); System.out.println("答案:" + answer1()); } //试卷第二题 public void testQuestion2(){ System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛"); System.out.println("答案:" + answer2()); } //试卷第三题 public void testQuestion3(){ System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴"); System.out.println("答案:" + answer3()); } //这三个钩子方法是给每个子类去实现,并返回答案的 public abstract String answer1(); public abstract String answer2(); public abstract String answer3(); //模板方法,考试的过程,定义基本的考试过程,子类回调 public void exam(){ testQuestion1(); testQuestion2(); testQuestion3(); } }
首先來看第一個學生的考試狀況
public class TestPaperA extends TestPaper{ @Override public String answer1() { return "A"; } @Override public String answer2() { return "B"; } @Override public String answer3() { return "D"; } }
其他學生的考卷可能答案不是一樣的,但是基本的答題過程就是一樣的,所以就不重複寫了,下面看下客戶端程式碼。
public class ShowAnswer { public static void main(String[] args) { TestPaper testPaper = new TestPaperA(); testPaper.exam(); } }
可以看待客戶端程式碼也減輕了很多,這樣邏輯清晰,利於維護,優勢很明顯,下面看下具體答題情況。
小龍女是楊過的什麼親戚? () A.小阿姨 B.大姨媽 C.姑姑 D.舅媽
答案:A
全真教的首任掌門是誰? A.周伯通 B.歐陽鋒 C.王重陽 D.西門吹牛
答案:B
《天龍八部》中被封為南院大王的大俠是誰? A.段譽B.喬峰C.慕容復D.段智興
答案:D
#3、模板方法模式的基本結構
AbstractClass是一個抽象類,其實就是一個抽像模板,定義並實作了一個模板方法。這個模板方法一般是一個具體的實現,他給了一些邏輯的骨架,而邏輯的組成在對應的抽象類別中,延後到了子類別實作。程式碼如下
public abstract class AbstractClass { //一些抽象行为,可以理解为重复不变的方法,提取到抽象类 public abstract void primitiveOperation1(); public abstract void primitiveOperation2(); //模板方法,给出了具体逻辑的骨架,而逻辑的组成是一些相应的抽象操作,他们都推迟到子类实现 public void templateMothed(){ primitiveOperation1(); primitiveOperation2(); } }
ConcreteClass,實作父類別所定義的一個或多個抽象方法。每一個AbstractClass都可以有一個或多個ConcreteClass與之對應,而每一個ConcreteClass都可以給出這些抽象方法(也就是骨架的組成步驟)的不同實現,從而得到的實現都不同。
public class ConcreteClassA extends AbstractClass{ @Override public void primitiveOperation1() { System.out.println("子类A的操作1"); } @Override public void primitiveOperation2() { System.out.println("子类A的操作2"); } }
public class ConcreteClassB extends AbstractClass{ @Override public void primitiveOperation1() { System.out.println("子类B的操作1"); } @Override public void primitiveOperation2() { System.out.println("子类B的操作2"); } }
上面定義了兩個具體的實現,更多的實現其實都是一致的,這裡就不多多說了。下面看下客戶端程式碼
public class Show { public static void main(String[] args) { AbstractClass c; c = new ConcreteClassA(); c.templateMothed(); c = new ConcreteClassB(); c.templateMothed(); } }
輸入如下
子類別A的操作1
子類別A的運算2
子類別B的運算1
子類別B的運算2
4、UML圖
#三、總結
範本方法模式就是為了將重複不變的程式碼提取到一個抽象類別中。當我們要完成在某一細節層次一致的一個過程或一系列步驟,但其個別步驟在更詳細的層次上的實作可能不同時,我們通常會考慮用模板方法模式來處理。
以上是java設計模式之模板方法模式詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!