一、什么是抽象工厂模式
抽象工厂模式为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
抽象工厂模式隶属于设计模式中的创建型模式,用于产品族的构建。抽象工厂是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂是指当有多个抽象角色时使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象。
为什么出现抽象工厂模式?
虽然工厂方法模式引入工厂等级结构,解决了简单工厂模式中工厂类职责过重的问题
,但由于工厂方法模式中每个工厂只创建一类具体类的对象
,如果需要的具体类很多时候,这将会导致系统当中的工厂类过多,这势必会增加系统的开销
。此时可以考虑将一些相关的具体类组成一个“具体类族”,由同一个工厂来统一生产
,这就是我们需要抽象工厂模式的原因。
实现原理
在抽象工厂模式中,客户端不再负责对象的创建,而是把这个责任丢给了具体的工厂类,客户端只负责对对象的调用,从而明确了各个类的职责。并且当一系列相互关联的产品被设计到一个工厂类里后,客户端的调用将会变得非常简单,而且,如果要更换这一系列的产品,则只需要更换一个工厂类即可。
二、抽象工厂模式的结构
角色 | 含义 |
---|---|
抽象工厂角色 | 担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的 |
具体工厂角色 | 这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的 |
抽象产品角色 | 担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口 |
具体产品角色 | 抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑 |
三、抽象工厂模式的代码实现
python实现
from abc import ABCMeta, abstractmethod
class CPU(metaclass=ABCMeta):
@abstractmethod
def show_cpu(self):
pass
class InterCPU(CPU):
def show_cpu(self):
print('this is inter cpu...')
class AmdCPU(CPU):
def show_cpu(self):
print('this is amd cpu...')
class OS(metaclass=ABCMeta):
@abstractmethod
def show_os(self):
pass
class AppleOS(OS):
def show_os(self):
print('this is apple os..')
class WindowsOS(OS):
def show_os(self):
print('this is windows os')
class Factory(metaclass=ABCMeta):
@abstractmethod
def make_cpu(self):
pass
@abstractmethod
def make_os(self):
pass
class Mac(Factory):
def make_cpu(self):
return AmdCPU()
def make_os(self):
return AppleOS()
class MacComputer(object):
def __init__(self, cpu, os):
self.cpu = cpu
self.os = os
def show_info(self):
print("电脑信息:")
self.cpu.show_cpu()
self.os.show_os()
def make_computer(factory):
cpu = factory.make_cpu()
os = factory.make_os()
return MacComputer(cpu, os)
mac = make_computer(Mac())
mac.show_info()
golang实现
package main
import "fmt"
// Programmer 程序员总称
type Programmer interface {
Work()
}
// FrontProgrammer 前端程序员
type FrontProgrammer struct {
Programmer
}
func (fp FrontProgrammer) Work() {
fmt.Println("this is FrontProgrammer work.")
}
// BackEndProgrammer 后端程序员
type BackendProgrammer struct {
Programmer
}
func (bp BackendProgrammer) Work() {
fmt.Println("this is BackendProgrammer work.")
}
// Architect 架构师总称
type Architect interface {
Design()
}
// FrontEndArchitect 前端架构师
type FrontArchitect struct {
Architect
}
func (fa FrontArchitect) Design() {
fmt.Println("this is FrontArchitect design.")
}
// BackEndArchitect 后端架构师
type BackendArchitect struct {
Architect
}
func (ba BackendArchitect) Design() {
fmt.Println("this is BackendArchitect design.")
}
// AbstractFactory 抽象工厂
type AbstractFactory interface {
CreateProgrammer() Programmer
CreateArchitect() Architect
}
// FrontEndFactory 前端工厂
type FrontFactory struct {
AbstractFactory
}
func (f *FrontFactory) CreateProgrammer() Programmer {
return FrontProgrammer{}
}
func (f *FrontFactory) CreateArchitect() Architect {
return FrontArchitect{}
}
// BackEndFactory 后端工厂
type BackendFactory struct {
AbstractFactory
}
func (b *BackendFactory) CreateProgrammer() Programmer {
return BackendProgrammer{}
}
func (b *BackendFactory) CreateArchitect() Architect {
return BackendArchitect{}
}
func main3() {
ff := FrontFactory{} // 定义前端工厂
fa := ff.CreateArchitect() // 定义前端架构师类
fp := ff.CreateProgrammer() // 定义前端程序员类
fmt.Println("前端组接到任务,开始工作...")
fa.Design() // 架构师开始工作
fp.Work() // 程序员开始工作
fmt.Println("后端组招到了一个程序员和一个架构师")
bf := BackendFactory{}
ba := bf.CreateArchitect()
bp := bf.CreateProgrammer()
fmt.Println("后端组接到任务,开始工作...")
ba.Design()
bp.Work()
}
四、抽象工厂模式的优缺点
优点
- 抽象工厂模式隔离了具体产品/类的生成, 使得客户并不需要知道什么被创建。 由于这种隔离,更换或增加一个具体工厂就变得相对容易, 所有的具体工厂都实现了抽象工厂中定义的那些公共接口, 因此只需改变具体工厂的实例, 就可以在某种程度上改变整个软件系统的行为。
- 当一个族中的多个对象被设计成一起工作时, 它能够保证客户端始终只使用同一个族中的对象
- 增加新的族很方便, 无须修改已有系统, 符合“开闭原则”
缺点
- 难以支持新种类的产品, 最大缺点就是产品族本身的扩展非常困难。如果在产品族中增加一个新的产品类型,则需要修改多个接口,并影响现已有的工厂类(
打个比方说,你要在这个工厂创建三个对象,原本只是创建两个对象的,那么你就要在抽象方法中添加一个创建对象的方法,那么所有实现了这个接口的类都是要重新添加这个创建对象的方法,这就是对之前的工厂有影响的原因。
)
五、抽象工厂模式的应用场景
- 当用户端需要创建的对象是一系列相互关联或相互依赖的产品族时,抽象工厂模式很适合应用这种情况
- 当系统中有多个产品族,但用户端每次只需要其中的某一族产品时,抽象工厂模式也非常适合这种情况
- 当系统中提供了产品的类库,且所有产品的接口相同时,要求客户端类不依赖产品实例的创建细节和内部结构时,抽象工厂也适合这种情况
六、对比
抽象工厂模式和工厂方法模式对比
总体而言:
工厂模式中的每一个形态都是针对一定问题的解决方案,工厂方法针对的是多个产品系列结构
抽象工厂模式针对的是多个产品族结构,一个产品族内有多个产品系列。
七、总结
抽象工厂模式是为用户端 提供一个创建一系列相关或相互依赖对象的接口,用户端无需知道他们需要的产品怎么做的,它只需要调用接口方法就行。
抽象工厂模式,不仅可以实现多个接口,而且每个工厂也可以生产多种产品类,和工厂方法模式一样,抽象工厂模式同样实现了开发封闭原则。
注意:当抽象工厂模式中的每个工厂类都只生产一种具体的产品时,这时候的抽象工厂模式相当于工厂方法模式。
通过接口规定每个具体工厂需要实现的方法,不需要考虑具体产品如何生成,将生成具体产品的细节放到具体工厂中取实现。当工厂生成产品需要更多的配置信息,将所有产品所需的配置信息都放在简单工厂中太过杂乱,也不便于代码维护。将生成某个产品的信息抽取出来,单独放到一个类中,每个具体工厂对应某个具体产品,使得具体工厂的职能更加单一,代码简洁。使信息局部化,降低了类的复杂性,变更引起的风险降低。