抽象工厂模式
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 88 课,共 107 课。
抽象工厂模式扩展了工厂模式,可以创建相关对象族,而无需指定它们的具体类型。你不再使用单个工厂函数,而是定义一个工厂接口,由多个具体工厂来实现,每个工厂都会生成一组彼此相关且一致的对象。
假设有一个 UI 工具包,需要创建按钮和复选框。不同的操作系统需要不同的实现方式,但这些组件必须保持一致地协同工作:
type Button interface {
Render() string
}
type Checkbox interface {
Check() string
}
// 抽象工厂接口
type GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}每个具体工厂都会生产一组相关组件:
// Windows 产品族
type WindowsButton struct{}
func (w WindowsButton) Render() string { return "Windows Button" }
type WindowsCheckbox struct{}
func (w WindowsCheckbox) Check() string { return "Windows Checkbox" }
type WindowsFactory struct{}
func (w WindowsFactory) CreateButton() Button { return WindowsButton{} }
func (w WindowsFactory) CreateCheckbox() Checkbox { return WindowsCheckbox{} }
// Mac 产品族
type MacButton struct{}
func (m MacButton) Render() string { return "Mac Button" }
type MacCheckbox struct{}
func (m MacCheckbox) Check() string { return "Mac Checkbox" }
type MacFactory struct{}
func (m MacFactory) CreateButton() Button { return MacButton{} }
func (m MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }客户端代码通过工厂接口进行操作,不依赖具体实现:
func BuildUI(factory GUIFactory) {
button := factory.CreateButton()
checkbox := factory.CreateCheckbox()
fmt.Println(button.Render(), checkbox.Check())
}当系统需要处理多个相关产品系列,并且你希望确保同一系列的组件搭配使用时,可以使用抽象工厂模式。它比简单工厂更复杂,所以只有在确实需要管理产品系列时才使用它。
挑战
简单让我们使用抽象工厂模式来构建一个家具店系统吧!你将创建能够生产相关家具系列的工厂:每个工厂都会生产风格一致的家具(现代或复古),确保同一家工厂生产的椅子和桌子在外观上相配。
你将把代码分成三个文件:
furniture.go:定义产品接口和具体的家具类型。创建两个产品接口:
Chair,包含方法SitOn() stringTable,包含方法PlaceItems() string
实现两个家具系列:
- 现代系列:
ModernChair返回Sitting on a sleek modern chair,ModernTable返回Placing items on a glass modern table - 复古系列:
VintageChair返回Sitting on an ornate vintage chair,VintageTable返回Placing items on a wooden vintage table
factory.go:定义抽象工厂接口和具体工厂。创建一个
FurnitureFactory接口,包含两个方法:CreateChair() ChairCreateTable() Table
实现两个具体工厂:
ModernFactory,生产ModernChair和ModernTableVintageFactory,生产VintageChair和VintageTable
另外,创建函数
GetFactory(style string) FurnitureFactory,根据风格(modern或vintage)返回相应的工厂。对于无法识别的风格,默认使用ModernFactory。main.go:使用工厂为房间配备家具。创建函数
FurnishRoom(factory FurnitureFactory) string,使用工厂创建椅子和桌子,然后返回一个格式化字符串,在两行中分别显示这两项操作。读取风格输入,获取相应的工厂,为房间配备家具,并打印结果。
输入如下:
- 第 1 行:家具风格(
modern、vintage或其他内容)
例如,输入:
modern输出应为:
Sitting on a sleek modern chair
Placing items on a glass modern table输入:
vintage输出应为:
Sitting on an ornate vintage chair
Placing items on a wooden vintage table输入:
rustic输出应为:
Sitting on a sleek modern chair
Placing items on a glass modern table注意,FurnishRoom 函数通过接口与任何工厂配合使用。它并不知道自己创建的是现代家具还是复古家具。这样可以确保房间里的所有家具都来自同一个系列,保持风格一致!
亲手试试
package main
import "fmt"
// FurnishRoom 使用工厂创建家具并返回结果
// TODO: 实现这个函数
// - 使用工厂创建一把椅子和一张桌子
// - 返回一个字符串,第一行是 SitOn() 的结果,第二行是 PlaceItems() 的结果
func FurnishRoom(factory FurnitureFactory) string {
// TODO: 使用工厂创建椅子和桌子
// TODO: 返回格式化的字符串,将两个操作的结果分别放在不同行
return ""
}
func main() {
var style string
fmt.Scanln(&style)
// TODO: 根据 style 获取合适的工厂
// TODO: 使用工厂布置房间
// TODO: 打印结果
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Go 在线编译器