一.背景
假設我們在做一款小型翻譯軟件,軟件可以將德語、英語、日語都翻譯成目標中文,並顯示在前端。
二.使用接口
我們會有三個具體的語言翻譯結構體,或許以後還有更多,但現在分別是German Translater、English Translater、Japanese Translater,他們都共同實現了一個接口Translator。
//翻譯接口
type Translator interface {
Translate(string) string
}
//德語翻譯類
type GermanTranslator struct{}
func (*GermanTranslator) Translate(words string) string {
return "德語"
}
//英語翻譯類
type EnglishTranslator struct{}
func (*EnglishTranslator) Translate(words string) string {
return "英語"
}
//日語翻譯類
type JapaneseTranslator struct{}
func (*JapaneseTranslator) Translate(words string) string {
return "日語"
}
接下來在程序入口獲取用戶輸入的文本,將其翻譯:
package main
import (
"fmt"
"time"
)
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
time.Sleep(3 * time.Second)
}()
var lan int
fmt.Printf("%s\r\n%s\r\n", "以下是可翻譯的語言種類,請輸入代表數字", "1:德語、2:英語、3:日語")
fmt.Scanln(&lan)
fmt.Println("請輸入要翻譯成中文的文本:")
var inputWords string
fmt.Scanln(&inputWords)
var translator Translator
//根據不同的語言種類,實例化不同的翻譯類
switch lan {
case 1:
translator = new(GermanTranslator)
case 2:
translator = new(EnglishTranslator)
case 3:
translator = new(JapaneseTranslator)
default:
panic("no such translator")
}
fmt.Println(translator.Translate(inputWords))
}
缺點:
- 違背了開閉原則,以後還可能有法語、俄語、阿拉伯語等其他翻譯器,每一次添加翻譯器都要在客戶端代碼增加對應的switch分支,維護成本高。倘若還有不止一處調用了創建邏輯,還要維護多處代碼。
- 違背了單一職責原則,客戶端處理類的職責應該只是負責接收用戶的輸入並將其打印,現在還負責翻譯類的創建邏輯,導致這個類的職責過多。
三.簡單工廠模式
設計原則:找出用中可能需要變化之處,並把它們獨立出來,不要和那些不需要變化的代碼混在一起。這樣的話,每次當新的需求來臨,我們只會改動到那些需要變化的地方,而不變的地方就不會被改動影響到。顯然,翻譯應用中容易變化的地方是生成翻譯類的邏輯,因此我們把這部分職責抽出來,把它交給另外一個類去做(一般是一個靜態方法),這個類就叫翻譯工廠。而客戶端再需要生成翻譯類實例時,僅需調用翻譯工廠提供的方法即可。就算以後翻譯工廠會提供更多的翻譯類,也不會修改到客戶端的代碼,因此也就有了我們的現在的簡單工廠模式。
簡單工廠模式:又稱爲靜態工廠方法(Static Factory Method)模式,它屬於類創建型模式。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。
UML類圖:
工廠代碼:
func CreateTranslator(lan int) Translator{
var translator Translator
//根據不同的語言種類,實例化不同的翻譯類
switch lan {
case 1:
translator = new(GermanTranslator)
case 2:
translator = new(EnglishTranslator)
case 3:
translator = new(JapaneseTranslator)
default:
panic("no such translator")
}
return translator
}
客戶端代碼:
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
time.Sleep(3 * time.Second)
}()
var lan int
fmt.Printf("%s\r\n%s\r\n", "以下是可翻譯的語言種類,請輸入代表數字", "1:德語、2:英語、3:日語")
fmt.Scanln(&lan)
fmt.Println("請輸入要翻譯成中文的文本:")
var inputWords string
fmt.Scanln(&inputWords)
//客戶端只關注如何獲取翻譯類,而不用關注創建翻譯類的細節
translator:=CreateTranslator(lan)
fmt.Println(translator.Translate(inputWords))
}
優點:
- 將客戶端和創建產品實例解耦開來,使客戶端只需要關注如何獲取實例。
- 符合單一職責。
缺點:
增加新翻譯類時還是需要改動工廠類,沒有符合開閉原則。
應用場景:
當在代碼裏看到switch的時候,就應該思考是否用簡單工廠模式