:::tips 本质上, 工厂模式是为了解决 相似类初始化和初始化十分复杂的情况
:::
使用场景
我们来看一下这样的场景, 现在需要翻译接口, 能够翻译, 大概会写出下面这样的代码
package mainimport ("fmt""time")//翻译接口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 "日语"}func main() {defer func() {if err := recover(); err != nil {fmt.Println(err)}time.Sleep(3 * time.Second)}()var lan intfmt.Printf("%s\r\n%s\r\n", "以下是可翻译的语言种类,请输入代表数字", "1:德语、2:英语、3:日语")fmt.Scanln(&lan)fmt.Println("请输入要翻译成中文的文本:")var inputWords stringfmt.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))}
- 违背了
开闭原则: 这样创建类, 如果添加了其他翻译类, 每次都需要更改客户端代码, 一次修改, 处处漏水 - 违背了
单一职责: 客户端应该只接受用户输入, 然后返回输出, 现在还需要负责类的创建
简单工厂模式
golang
我们使用简单工厂模式进行改写
package mainimport ("fmt""time")//翻译接口type Translator interface {Translate(string) string}func CreatTranslator(lan int) Translator {var translator Translatorswitch lan {case 1: translator = new(GermanTranslator)case 2: translator = new(EnglishTranslator)case 3: translator = new(JapaneseTranslator)}return translator}//德语翻译类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 "日语"}func main() {defer func() {if err := recover(); err != nil {fmt.Println(err)}time.Sleep(3 * time.Second)}()var lan intfmt.Printf("%s\r\n%s\r\n", "以下是可翻译的语言种类,请输入代表数字", "1:德语、2:英语、3:日语")fmt.Scanln(&lan)fmt.Println("请输入要翻译成中文的文本:")var inputWords stringfmt.Scanln(&inputWords)translator := CreatTranslator(lan)fmt.Println(translator.Translate(inputWords))}
- 上面还需要检测工厂产出的是否成功, 这里没有写
- 改写后, 职责划分更加清晰, 业务代码中不再负责类创建, 符合了
单一职责原则 - 但是, 新增类的时候依然需要修改整个工厂类, 不符合
开闭原则, 不过也需要根据场景来进行取舍, 如果这里不会增加太多新方法, 那么即便不符合也死能够接受的, 因为要完全符合原则, 会牺牲代码可读性提高代码复杂度
工厂模式
golang
golang没有继承, 基于匿名组合完成
package mainimport ("fmt""time")// Translator 翻译接口type Translator interface {Translate(string) string}// TranslatorFactory 工厂接口type TranslatorFactory interface {Create() Translator}// TranslatorBase 是 Translator接口实现的基类, 封装公用方法type TranslatorBase struct {}func (*TranslatorBase) PublicMethod() string {return "public"}// GermanTranslatorFactory 德语翻译类工厂type GermanTranslatorFactory struct{}func (GermanTranslatorFactory) Create() Translator {return &GermanTranslator{TranslatorBase:&TranslatorBase{},}}// GermanTranslator 德语翻译类type GermanTranslator struct{*TranslatorBase}func (g *GermanTranslator) Translate(words string) string {g.PublicMethod()return "德语"}// EnglishTranslatorFactory 英语翻译类工厂type EnglishTranslatorFactory struct{}func (EnglishTranslatorFactory) Create() Translator {return &EnglishTranslator{TranslatorBase:&TranslatorBase{},}}// EnglishTranslator 英语翻译类type EnglishTranslator struct{*TranslatorBase}func (e *EnglishTranslator) Translate(words string) string {e.PublicMethod()return "英语"}// JapaneseTranslatorFactory 日语翻译类工厂type JapaneseTranslatorFactory struct{}func (JapaneseTranslatorFactory) Create() Translator {return &JapaneseTranslator{TranslatorBase:&TranslatorBase{},}}// JapaneseTranslator 日语翻译类type JapaneseTranslator struct{*TranslatorBase}func (j *JapaneseTranslator) Translate(words string) string {j.PublicMethod()return "日语"}func main() {defer func() {if err := recover(); err != nil {fmt.Println(err)}time.Sleep(3 * time.Second)}()var lan intfmt.Printf("%s\r\n%s\r\n", "以下是可翻译的语言种类,请输入代表数字", "1:德语、2:英语、3:日语")fmt.Scanln(&lan)fmt.Println("请输入要翻译成中文的文本:")var inputWords stringfmt.Scanln(&inputWords)switch lan {case 1: TranslatorFuc(GermanTranslatorFactory{}, "1")case 2: TranslatorFuc(EnglishTranslatorFactory{}, "2")case 3: TranslatorFuc(JapaneseTranslatorFactory{}, "3")}}func TranslatorFuc(factory TranslatorFactory, input string){fmt.Println(factory.Create().Translate(input))}
- 工厂模式多了很多代码, 主要每一个类都需要一个工厂, 这里其实导致了类的膨胀, 过多的类给维护带来了麻烦
- 在构造并不复杂的情况下, 工厂模式其实不如简单工厂来得直接
- 并且这里使用工厂之后, 逻辑又被混入到业务代码中了, 这样是不行的, 你还需要封装出一个创建工厂的工厂
:::tips 这里就体现了过度设计的弊端, 如果构造类并不复杂, 很多时候简单工厂比工厂要实用很多
:::
