抽象工厂模式 (Abstract Factory Pattern)
意图
抽象工厂模式是一种创建型设计模式,它提供一个创建一系列相关或依赖对象的接口,而无需指定它们具体的类。通过使用抽象工厂,客户端可以在不修改代码的情况下使用不同的产品系列。
问题
在现实世界中,考虑一个跨平台的图形用户界面(GUI)框架。该框架需要支持多个平台(如Windows、macOS、Linux),每个平台都有一组特定的控件(如按钮、文本框、复选框等)。如果在主应用中硬编码这些控件,会导致代码难以维护和扩展。
解决方案
使用抽象工厂模式,我们可以定义一个控件工厂接口和多个具体平台的控件工厂实现类,通过抽象工厂创建相关的控件对象,从而使得客户端代码与具体的平台无关。
模式结构
- 抽象产品(AbstractProduct):定义产品的接口,例如按钮、文本框等。
- 具体产品(ConcreteProduct):实现产品接口的具体产品类,例如Windows按钮、macOS按钮、Linux按钮等。
- 抽象工厂(AbstractFactory):声明创建一组相关产品对象的工厂方法。
- 具体工厂(ConcreteFactory):实现抽象工厂接口的具体工厂类,负责实例化具体的产品对象。
代码
以下是使用Go语言实现的抽象工厂模式示例:
package main
import "fmt"
// Button 是按钮的抽象产品接口
type Button interface {
Render() string
}
// TextBox 是文本框的抽象产品接口
type TextBox interface {
Render() string
}
// WindowsButton 是具体产品 - Windows 按钮
type WindowsButton struct{}
func (wb *WindowsButton) Render() string {
return "Rendering Windows Button"
}
// WindowsTextBox 是具体产品 - Windows 文本框
type WindowsTextBox struct{}
func (wtb *WindowsTextBox) Render() string {
return "Rendering Windows TextBox"
}
// MacOSButton 是具体产品 - macOS 按钮
type MacOSButton struct{}
func (mb *MacOSButton) Render() string {
return "Rendering macOS Button"
}
// MacOSTextBox 是具体产品 - macOS 文本框
type MacOSTextBox struct{}
func (mtb *MacOSTextBox) Render() string {
return "Rendering macOS TextBox"
}
// LinuxButton 是具体产品 - Linux 按钮
type LinuxButton struct{}
func (lb *LinuxButton) Render() string {
return "Rendering Linux Button"
}
// LinuxTextBox 是具体产品 - Linux 文本框
type LinuxTextBox struct{}
func (ltb *LinuxTextBox) Render() string {
return "Rendering Linux TextBox"
}
// GUIFactory 是抽象工厂接口
type GUIFactory interface {
CreateButton() Button
CreateTextBox() TextBox
}
// WindowsFactory 是具体工厂类 - Windows 工厂
type WindowsFactory struct{}
func (wf *WindowsFactory) CreateButton() Button {
return &WindowsButton{}
}
func (wf *WindowsFactory) CreateTextBox() TextBox {
return &WindowsTextBox{}
}
// MacOSFactory 是具体工厂类 - macOS 工厂
type MacOSFactory struct{}
func (mf *MacOSFactory) CreateButton() Button {
return &MacOSButton{}
}
func (mf *MacOSFactory) CreateTextBox() TextBox {
return &MacOSTextBox{}
}
// LinuxFactory 是具体工厂类 - Linux 工厂
type LinuxFactory struct{}
func (lf *LinuxFactory) CreateButton() Button {
return &LinuxButton{}
}
func (lf *LinuxFactory) CreateTextBox() TextBox {
return &LinuxTextBox{}
}
// main 函数演示了抽象工厂模式的使用
func main() {
var factory GUIFactory
// 使用 Windows 工厂
factory = &WindowsFactory{}
button := factory.CreateButton()
textBox := factory.CreateTextBox()
fmt.Println(button.Render())
fmt.Println(textBox.Render())
// 使用 macOS 工厂
factory = &MacOSFactory{}
button = factory.CreateButton()
textBox = factory.CreateTextBox()
fmt.Println(button.Render())
fmt.Println(textBox.Render())
// 使用 Linux 工厂
factory = &LinuxFactory{}
button = factory.CreateButton()
textBox = factory.CreateTextBox()
fmt.Println(button.Render())
fmt.Println(textBox.Render())
}
适用场景
- 需要创建一系列相关或互相依赖的对象时。
- 系统需要独立于产品的创建和组合方式时。
- 需要提供一个产品类库,且只显示它们的接口而不是实现时。
实现方式
- 创建抽象产品接口,定义产品的通用行为。
- 创建具体产品类,实现抽象产品接口。
- 创建抽象工厂接口,声明创建产品对象的工厂方法。
- 创建具体工厂类,实现抽象工厂接口,负责实例化具体的产品对象。
优缺点
优点:
- 分离了具体类的创建,使得代码更容易维护和扩展。
- 符合单一职责原则,工厂类只负责对象的创建。
- 遵循开闭原则,可以通过添加新的具体工厂和具体产品类来扩展系统,而不修改已有代码。
缺点:
- 每增加一组产品类,就需要增加相应的具体工厂类,增加了代码量。
其他模式的关系
- 工厂方法模式(Factory Method Pattern):抽象工厂模式通常与工厂方法模式一起使用,具体工厂类可以使用工厂方法来创建具体产品对象。
- 单例模式(Singleton Pattern):具体工厂类可以使用单例模式来确保每个具体工厂只有一个实例。
- 依赖注入(Dependency Injection):抽象工厂模式可以与依赖注入一起使用,将具体工厂对象注入到客户端代码中。