Go和Java實現模板模式
下面通過一個游戲的例子來說明模板模式的使用。
1、模板模式
在模板模式中,一個抽象類公開定義了執行它的方法的方式/模板。它的子類可以按需要重寫方法實現,但調用將
以抽象類中定義的方式進行。這種類型的設計模式屬于行為型模式。
-
意圖:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的
結構即可重定義該算法的某些特定步驟。
-
主要解決:一些方法通用,卻在每一個子類都重新寫了這一方法。
-
何時使用:有一些通用的方法。
-
如何解決:將這些通用算法抽象出來。
-
關鍵代碼:在抽象類實現,其他步驟在子類實現。
-
應用實例:1、在造房子的時候,地基、走線、水管都一樣,只有在建筑的后期才有加壁櫥加柵欄等差異。
2、西游記里面菩薩定好的 81 難,這就是一個頂層的邏輯骨架。 3、spring 中對 Hibernate 的支持,將一些
已經定好的方法封裝起來,比如開啟事務、獲取 Session、關閉 Session 等,程序員不重復寫那些已經規范好
的代碼,直接丟一個實體就可以保存。
-
優點:1、封裝不變部分,擴展可變部分。 2、提取公共代碼,便于維護。 3、行為由父類控制,子類實現。
-
缺點:每一個不同的實現都需要一個子類來實現,導致類的個數增加,使得系統更加龐大。
-
使用場景:1、有多個子類共有的方法,且邏輯相同。 2、重要的、復雜的方法,可以考慮作為模板方法。
-
注意事項:為防止惡意操作,一般模板方法都加上 final 關鍵詞。
-
適用性:
一次性實現一個算法的不變的部分,并將可變的行為留給子類來實現。
各子類中公共的行為應被提取出來并集中到一個公共父類中以避免代碼重復,首先識別現有代碼中的不同之
處,并且將不同之處分離為新的操作。最后用一個調用這些新的操作的模板方法來替換這些不同的代碼。
控制子類擴展。
2、Go實現模板模式
package templatemethod// ========== 創建一個抽象類,它的模板方法被設置為 final ==========
// ========== Game ==========
type Game interface {Initialize()StartPlay()EndPlay()Play()
}
package templatemethod// ========== BaseGame ==========
type BaseGame struct {Game
}func (b *BaseGame) Initialize() {
}func (b *BaseGame) StartPlay() {
}func (b *BaseGame) EndPlay() {
}func (b *BaseGame) Play() {b.Game.Initialize()b.Game.StartPlay()b.Game.EndPlay()
}
package templatemethodimport "fmt"// ========== Cricket ==========
type Cricket struct {BaseGame
}func (c *Cricket) Initialize() {fmt.Println("Cricket Game Initialized! Start playing.")
}func (c *Cricket) StartPlay() {fmt.Println("Cricket Game Started. Enjoy the game!")
}func (c *Cricket) EndPlay() {fmt.Println("Cricket Game Finished!")
}func (c *Cricket) Play() {c.BaseGame.Play()
}
package templatemethodimport "fmt"// ========== Football ==========
type Football struct {BaseGame
}func (f *Football) Initialize() {fmt.Println("Football Game Initialized! Start playing.")
}func (f *Football) StartPlay() {fmt.Println("Football Game Started. Enjoy the game!")
}func (f *Football) EndPlay() {fmt.Println("Football Game Finished!")
}func (f *Football) Play() {f.BaseGame.Play()
}
package mainimport ("fmt". "proj/templatemethod"
)func main() {var baseGame BaseGamecricket := Cricket{}baseGame = BaseGame{Game: &cricket}cricket.BaseGame = baseGamecricket.Play()fmt.Println("")football := Football{}baseGame = BaseGame{Game: &football}football.BaseGame = baseGamefootball.Play()
}
# 程序輸出
Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!
3、Java實現模板模式
package com.templatemethod;// ========== 創建一個抽象類,它的模板方法被設置為 final ==========
// ========== Game ==========
public abstract class Game {abstract void initialize();abstract void startPlay();abstract void endPlay();// 模板public final void play() {// 初始化游戲initialize();// 開始游戲startPlay();// 結束游戲endPlay();}
}
package com.templatemethod;// ========== Cricket ==========
public class Cricket extends Game {@Overridevoid endPlay() {System.out.println("Cricket Game Finished!");}@Overridevoid initialize() {System.out.println("Cricket Game Initialized! Start playing.");}@Overridevoid startPlay() {System.out.println("Cricket Game Started. Enjoy the game!");}
}
package com.templatemethod;// ========== Football ==========
public class Football extends Game {@Overridevoid endPlay() {System.out.println("Football Game Finished!");}@Overridevoid initialize() {System.out.println("Football Game Initialized! Start playing.");}@Overridevoid startPlay() {System.out.println("Football Game Started. Enjoy the game!");}
}
package com.templatemethod;public class Test {public static void main(String[] args) {Game game = new Cricket();game.play();System.out.println();game = new Football();game.play();}
}
# 程序輸出
Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!