工廠模式三種類型:
一、簡單工廠模式(Simple Factory)
定義: 用一個工廠類,根據傳入的參數決定創建哪一種具體產品類實例。
面試說法: 由一個統一的工廠創建所有對象,增加新產品時需要修改工廠類,不符合OCP開閉原則。
OCP原則:
對擴展開放(Open for extension):軟件中的功能應該允許通過新增代碼來進行擴展。
對修改關閉(Closed for modification):原有代碼不應該被修改,以減少引入 bug 的風險。
Go 實現:
type PayMethod interface {Pay(amount float64)
}type AliPay struct{}
func (a *AliPay) Pay(amount float64) {fmt.Println("使用支付寶支付", amount)
}type WeChatPay struct{}
func (w *WeChatPay) Pay(amount float64) {fmt.Println("使用微信支付", amount)
}func PayFactory(channel string) PayMethod {switch channel {case "alipay":return &AliPay{}case "wechat":return &WeChatPay{}default:return nil}
}
二、工廠方法模式(Factory Method)
定義: 把創建對象的邏輯下放到每個具體工廠類,遵循了開閉原則。
面試說法: 一個抽象工廠接口 + 多個具體工廠類,每種產品由對應工廠類負責創建。符合開閉原則,新增產品時不修改已有代碼,只需新增工廠類。
Go 實現:
type PayMethod interface {Pay(amount float64)
}type PayFactory interface {CreatePayMethod() PayMethod
}type AliPay struct{}
func (a *AliPay) Pay(amount float64) {fmt.Println("使用支付寶支付", amount)
}type AliPayFactory struct{}
func (f *AliPayFactory) CreatePayMethod() PayMethod {return &AliPay{}
}type WeChatPay struct{}
func (w *WeChatPay) Pay(amount float64) {fmt.Println("使用微信支付", amount)
}type WeChatPayFactory struct{}
func (f *WeChatPayFactory) CreatePayMethod() PayMethod {return &WeChatPay{}
}
三、抽象工廠模式(Abstract Factory)
定義: 提供一系列產品創建的接口,每個具體工廠創建一整套產品。
面試說法: 用于創建一系列相關產品,適用于產品族的擴展。每個工廠可以返回多個產品實例,如 UI 工廠創建按鈕、窗口、滾動條等。
Go 實現:
// 抽象產品
type Pay interface {Pay(amount float64)
}
type Refund interface {Refund(amount float64)
}// 抽象工廠
type PayFactory interface {CreatePay() PayCreateRefund() Refund
}// 支付寶產品實現
type AliPay struct{}
func (a *AliPay) Pay(amount float64) {fmt.Println("支付寶支付", amount)
}
type AliRefund struct{}
func (a *AliRefund) Refund(amount float64) {fmt.Println("支付寶退款", amount)
}// 支付寶工廠
type AliFactory struct{}
func (f *AliFactory) CreatePay() Pay {return &AliPay{}
}
func (f *AliFactory) CreateRefund() Refund {return &AliRefund{}
}
面試中該如何答工廠模式的區別?
-
簡單工廠模式
- 優點:結構簡單,適用于產品數量較少、需求變化不頻繁的場景。
- 缺點:不符合開閉原則,新增產品需要修改工廠代碼。
- 應用場景:支付渠道種類少的項目、快速原型開發。
-
工廠方法模式
- 優點:符合開閉原則,新增產品時只需新增具體工廠類,擴展性好。
- 缺點:類的數量增加,結構相對復雜。
- 應用場景:產品頻繁擴展變化的系統,例如支持多個支付渠道,未來還會新增。
-
抽象工廠模式
- 優點:可以創建一整套相關聯的產品(產品族),一致性強。
- 缺點:不方便支持新增產品種類(每個工廠都要改),靈活性略低。
- 應用場景:跨平臺開發、UI 工具包、數據庫驅動(同一工廠生產連接器和執行器等)。
“簡單工廠是最基本的一種模式,用一個工廠創建所有對象,不符合開閉原則。工廠方法將創建邏輯分離到每個工廠類,支持擴展。抽象工廠則用于生產一組相關產品,產品族統一,適合跨平臺系統。”
工廠模式:
? 通常只有一個抽象工廠接口和多個具體工廠實現類,每個工廠創建一種產品。
抽象工廠模式:
? 有一個抽象工廠接口,多個具體工廠實現類,每個工廠創建一個產品族。
? 強調產品之間的 “族” 關系(如 Windows 風格的按鈕 + 復選框必須來自同一個工廠)。
// 抽象產品族
type Button interface { Click() }
type Checkbox interface { Check() }// 具體產品(按族分類)
type WindowsButton struct{}
type WindowsCheckbox struct{}
type MacButton struct{}
type MacCheckbox struct{}// 抽象工廠
type GUIFactory interface {CreateButton() ButtonCreateCheckbox() Checkbox
}// 具體工廠
type WindowsFactory struct{} // 創建Windows風格的Button和Checkbox
type MacFactory struct{} // 創建Mac風格的Button和Checkbox
四、單例模式(Singleton Pattern)
定義:
確保一個類只有一個實例,并提供一個全局訪問點。
使用場景:
- 配置管理類
- 數據庫連接池
- 日志處理類
- 緩存管理器
特點:
- 全局唯一
- 延遲初始化(懶漢)
- 線程安全
Go 語言實現(懶漢 + 線程安全):
package singletonimport ("sync"
)type Singleton struct {Name string
}var (instance *Singletononce sync.Once
)func GetInstance() *Singleton {once.Do(func() {instance = &Singleton{Name: "唯一實例"}})return instance
}
單例模式確保某個類在整個系統中只有一個實例。常用
sync.Once
來實現線程安全的延遲初始化。在場景如日志記錄器、配置加載器中很常見。它的關鍵是將構造函數私有化,通過提供一個全局訪問方法來獲取實例。
餓漢
package singletontype EagerSingleton struct {Name string
}var eagerInstance = &EagerSingleton{Name: "餓漢式單例"}func GetEagerInstance() *EagerSingleton {return eagerInstance
}
- 懶漢式在第一次使用時才初始化,需要注意并發下的線程安全,Go 中推薦使用 sync.Once 來保證只初始化一次;
- 餓漢式在程序啟動時就創建實例,線程安全但資源利用不夠高效。適合對資源敏感性不強的場景。
實際開發中,推薦懶漢式 + sync.Once 方式來兼顧延遲加載和線程安全。
五、代理模式(Proxy Pattern)
定義:
為其他對象提供一個“代理”以控制對該對象的訪問。
使用場景:
- 訪問控制(權限校驗)
- 延遲加載(虛擬代理)
- 遠程代理(RPC Stub)
- 緩存代理(避免重復計算)
Go 語言實現(以下載器為例,帶緩存功能的代理):
package proxyimport "fmt"type Downloader interface {Download(url string)
}// 真實對象
type RealDownloader struct{}func (r *RealDownloader) Download(url string) {fmt.Println("正在下載:", url)
}// 代理對象
type ProxyDownloader struct {real *RealDownloadercacheMap map[string]bool
}func NewProxyDownloader() *ProxyDownloader {return &ProxyDownloader{real: &RealDownloader{},cacheMap: make(map[string]bool),}
}func (p *ProxyDownloader) Download(url string) {if p.cacheMap[url] {fmt.Println("緩存命中:", url)} else {p.real.Download(url)p.cacheMap[url] = true}
}
代理模式通過引入一個代理對象來控制對目標對象的訪問。比如在緩存代理中,代理會先判斷是否命中緩存,如果沒有才真正訪問目標對象。這樣可以在不改動原有邏輯的情況下,增強對象的功能(控制、緩存、權限等)。
https://github.com/0voice