舉個慄子 問題描述 小時候數學老師的隨堂測驗,都是在黑板上抄題目,然後再作答案。寫一個抄題目的程式。 簡單實現 學生甲抄的試卷 學生乙抄的試卷 測試 測試結果 存在問題 兩個學生抄試卷都非常類似,除了答案不同,沒什麼不一樣,這樣又容易錯,又難以維護。因此老師出一份試卷,列印多份,讓學生填寫答案就可以 ...
舉個慄子
問題描述
小時候數學老師的隨堂測驗,都是在黑板上抄題目,然後再作答案。寫一個抄題目的程式。
簡單實現
學生甲抄的試卷
/**
* 學生甲抄的試卷
* Created by callmeDevil on 2019/7/14.
*/
public class TestPaperA {
// 試題1
public void testQuestion1(){
System.out.println("路飛在頂上戰爭之後,修煉了多久? a.3天 b.2年 c.2天 d.3年");
System.out.println("答案:b");
}
// 試題2
public void testQuestion2(){
System.out.println("鳴人是第幾代火影? a.六代 b.七代 c.八代 d.九代");
System.out.println("答案:b");
}
}
學生乙抄的試卷
/**
* 學生乙抄的試卷
* Created by callmeDevil on 2019/7/14.
*/
public class TestPaperB {
// 試題1
public void testQuestion1(){
System.out.println("路飛在頂上戰爭之後,修煉了多久? a.3天 b.2年 c.2天 d.3年");
System.out.println("答案:a");
}
// 試題2
public void testQuestion2(){
System.out.println("鳴人是第幾代火影? a.六代 b.七代 c.八代 d.九代");
System.out.println("答案:a");
}
}
測試
public class Test {
public static void main(String[] args) {
System.out.println("學生甲抄的試卷:");
TestPaperA studentA = new TestPaperA();
studentA.testQuestion1();
studentA.testQuestion2();
System.out.println("學生乙抄的試卷:");
TestPaperB studentB = new TestPaperB();
studentB.testQuestion1();
studentB.testQuestion2();
}
}
測試結果
學生甲抄的試卷:
路飛在頂上戰爭之後,修煉了多久? a.3天 b.2年 c.2天 d.3年
答案:b
鳴人是第幾代火影? a.六代 b.七代 c.八代 d.九代
答案:b
學生乙抄的試卷:
路飛在頂上戰爭之後,修煉了多久? a.3天 b.2年 c.2天 d.3年
答案:a
鳴人是第幾代火影? a.六代 b.七代 c.八代 d.九代
答案:a
存在問題
兩個學生抄試卷都非常類似,除了答案不同,沒什麼不一樣,這樣又容易錯,又難以維護。因此老師出一份試卷,列印多份,讓學生填寫答案就可以了。應該把試題和答案分離,抽出一個父類,讓兩個子類繼承它,公共的試題代碼寫到父類當中就行了。
提煉代碼
試題父類
/**
* 試題父類-動漫考題
* Created by callmeDevil on 2019/7/14.
*/
public class TestPaper {
// 試題1
public void testQuestion1(){
System.out.println("路飛在頂上戰爭之後,修煉了多久? a.3天 b.2年 c.2天 d.3年");
}
// 試題2
public void testQuestion2(){
System.out.println("鳴人是第幾代火影? a.六代 b.七代 c.八代 d.九代");
}
}
學生甲抄的試卷-版本2
/**
* 學生甲抄的試卷-版本2
* Created by callmeDevil on 2019/7/14.
*/
public class TestPaperA2 extends TestPaper{
@Override
public void testQuestion1() {
super.testQuestion1();
System.out.println("答案:b");
}
@Override
public void testQuestion2() {
super.testQuestion2();
System.out.println("答案:b");
}
}
學生乙抄的試卷-版本2
/**
* 學生乙抄的試卷-版本2
* Created by callmeDevil on 2019/7/14.
*/
public class TestPaperB2 extends TestPaper{
@Override
public void testQuestion1(){
super.testQuestion1();
System.out.println("答案:a");
}
@Override
public void testQuestion2(){
super.testQuestion2();
System.out.println("答案:a");
}
}
客戶端測試代碼與測試結果此處省略,同上述簡單實現。
存在的問題
- 既然用了繼承,並且肯定這個繼承有意義,就應該要成為子類的模板,所有重覆的代碼都應該要上升到父類去,而不是讓每個子類都去重覆
- 當我們要完成在某一個細節層次一致的一個過程或一系列步驟,但其個別步驟在更詳細的層次上的實現可能不同時,我們通常考慮用模板方法模式來處理
- 在上面提煉的代碼中,每個學生只是輸出的答案不同,其他全部都是一樣的,應該在此處改成一個虛方法,讓每個子類去重寫即可
模板方法模式
定義
定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定的步驟。
UML圖
代碼實現
模板方法父類-動漫考題
/**
* 模板方法父類-動漫考題
* Created by callmeDevil on 2019/7/14.
*/
public abstract class TestPaper {
// 試題1
public void testQuestion1(){
System.out.println("路飛在頂上戰爭之後,修煉了多久? a.3天 b.2年 c.2天 d.3年");
System.out.println("答案:" + answer1());//改成一個虛方法,下同
}
// 試題2
public void testQuestion2(){
System.out.println("鳴人是第幾代火影? a.六代 b.七代 c.八代 d.九代");
System.out.println("答案:" + answer2());
}
// 此方法的目的就是給繼承的子類重寫,因為這裡每個人的答案都是不同的
public abstract String answer1();
public abstract String answer2();
}
學生甲抄的試卷-模板方法實現
/**
* 學生甲抄的試卷-模板方法實現
* Created by callmeDevil on 2019/7/14.
*/
public class TestPaperA3 extends TestPaper{
@Override
public String answer1() {
return "b";
}
@Override
public String answer2() {
return "b";
}
}
學生乙抄的試卷-模板方法實現
/**
* 學生乙抄的試卷-模板方法實現
* Created by callmeDevil on 2019/7/14.
*/
public class TestPaperB3 extends TestPaper{
@Override
public String answer1() {
return "a";
}
@Override
public String answer2() {
return "a";
}
}
模板方法測試
/**
* 模板方法測試
* Created by callmeDevil on 2019/7/14.
*/
public class Test3 {
public static void main(String[] args) {
System.out.println("學生甲抄的試卷:");
// 將子類變數的聲明改成父類,利用多態性實現了代碼的復用
TestPaper studentA = new TestPaperA3();
studentA.testQuestion1();
studentA.testQuestion2();
System.out.println("學生乙抄的試卷:");
TestPaper studentB = new TestPaperB3();
studentB.testQuestion1();
studentB.testQuestion2();
}
}
測試結果是一致的,此處不再貼出。
總結
- 模板方法模式是通過把不變的行為搬移到父類,去除子類中重覆的代碼來體現它的優勢
- 模板方法模式就是提供了一個很好的代碼復用平臺
- 當不變的和可變的行為在方法的子類實現中混合在一起的時候,不變的行為就會在子類中重覆出現。我們通過模板方法模式把這些行為搬移到單一的地方,這樣就幫助子類擺脫重覆的不變行為的糾纏。