一、什么是抽象工廠模式
抽象工廠模式為創(chuàng)建一組相關(guān)或相互依賴的對象提供一個接口,而且無需指定他們的具體類。
抽象工廠模式隸屬于設(shè)計(jì)模式中的創(chuàng)建型模式,用于產(chǎn)品族的構(gòu)建。抽象工廠是所有形態(tài)的工廠模式中最為抽象和最具一般性的一種形態(tài)。抽象工廠是指當(dāng)有多個抽象角色時使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個接口,使客戶端在不必指定產(chǎn)品的具體情況下,創(chuàng)建多個產(chǎn)品族中的產(chǎn)品對象。
為什么出現(xiàn)抽象工廠模式?
雖然工廠方法模式引入工廠等級結(jié)構(gòu),解決了簡單工廠模式中工廠類職責(zé)過重的問題
,但由于工廠方法模式中每個工廠只創(chuàng)建一類具體類的對象
,如果需要的具體類很多時候,這將會導(dǎo)致系統(tǒng)當(dāng)中的工廠類過多,這勢必會增加系統(tǒng)的開銷
。此時可以考慮將一些相關(guān)的具體類組成一個“具體類族”,由同一個工廠來統(tǒng)一生產(chǎn)
,這就是我們需要抽象工廠模式的原因。
實(shí)現(xiàn)原理
在抽象工廠模式中,客戶端不再負(fù)責(zé)對象的創(chuàng)建,而是把這個責(zé)任丟給了具體的工廠類,客戶端只負(fù)責(zé)對對象的調(diào)用,從而明確了各個類的職責(zé)。并且當(dāng)一系列相互關(guān)聯(lián)的產(chǎn)品被設(shè)計(jì)到一個工廠類里后,客戶端的調(diào)用將會變得非常簡單,而且,如果要更換這一系列的產(chǎn)品,則只需要更換一個工廠類即可。
二、抽象工廠模式的結(jié)構(gòu)
角色 | 含義 |
---|---|
抽象工廠角色 | 擔(dān)任這個角色的是工廠方法模式的核心,它是與應(yīng)用系統(tǒng)商業(yè)邏輯無關(guān)的 |
具體工廠角色 | 這個角色直接在客戶端的調(diào)用下創(chuàng)建產(chǎn)品的實(shí)例。這個角色含有選擇合適的產(chǎn)品對象的邏輯,而這個邏輯是與應(yīng)用系統(tǒng)的商業(yè)邏輯緊密相關(guān)的 |
抽象產(chǎn)品角色 | 擔(dān)任這個角色的類是工廠方法模式所創(chuàng)建的對象的父類,或它們共同擁有的接口 |
具體產(chǎn)品角色 | 抽象工廠模式所創(chuàng)建的任何產(chǎn)品對象都是某一個具體產(chǎn)品類的實(shí)例。這是客戶端最終需要的東西,其內(nèi)部一定充滿了應(yīng)用系統(tǒng)的商業(yè)邏輯 |
三、抽象工廠模式的代碼實(shí)現(xiàn)
python實(shí)現(xiàn)
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實(shí)現(xiàn)
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 架構(gòu)師總稱
type Architect interface {
Design()
}
// FrontEndArchitect 前端架構(gòu)師
type FrontArchitect struct {
Architect
}
func (fa FrontArchitect) Design() {
fmt.Println("this is FrontArchitect design.")
}
// BackEndArchitect 后端架構(gòu)師
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() // 定義前端架構(gòu)師類
fp := ff.CreateProgrammer() // 定義前端程序員類
fmt.Println("前端組接到任務(wù),開始工作...")
fa.Design() // 架構(gòu)師開始工作
fp.Work() // 程序員開始工作
fmt.Println("后端組招到了一個程序員和一個架構(gòu)師")
bf := BackendFactory{}
ba := bf.CreateArchitect()
bp := bf.CreateProgrammer()
fmt.Println("后端組接到任務(wù),開始工作...")
ba.Design()
bp.Work()
}
四、抽象工廠模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 抽象工廠模式隔離了具體產(chǎn)品/類的生成, 使得客戶并不需要知道什么被創(chuàng)建。 由于這種隔離,更換或增加一個具體工廠就變得相對容易, 所有的具體工廠都實(shí)現(xiàn)了抽象工廠中定義的那些公共接口, 因此只需改變具體工廠的實(shí)例, 就可以在某種程度上改變整個軟件系統(tǒng)的行為。
- 當(dāng)一個族中的多個對象被設(shè)計(jì)成一起工作時, 它能夠保證客戶端始終只使用同一個族中的對象
- 增加新的族很方便, 無須修改已有系統(tǒng), 符合“開閉原則”
缺點(diǎn)
- 難以支持新種類的產(chǎn)品, 最大缺點(diǎn)就是產(chǎn)品族本身的擴(kuò)展非常困難。如果在產(chǎn)品族中增加一個新的產(chǎn)品類型,則需要修改多個接口,并影響現(xiàn)已有的工廠類(
打個比方說,你要在這個工廠創(chuàng)建三個對象,原本只是創(chuàng)建兩個對象的,那么你就要在抽象方法中添加一個創(chuàng)建對象的方法,那么所有實(shí)現(xiàn)了這個接口的類都是要重新添加這個創(chuàng)建對象的方法,這就是對之前的工廠有影響的原因。
)
五、抽象工廠模式的應(yīng)用場景
- 當(dāng)用戶端需要創(chuàng)建的對象是一系列相互關(guān)聯(lián)或相互依賴的產(chǎn)品族時,抽象工廠模式很適合應(yīng)用這種情況
- 當(dāng)系統(tǒng)中有多個產(chǎn)品族,但用戶端每次只需要其中的某一族產(chǎn)品時,抽象工廠模式也非常適合這種情況
- 當(dāng)系統(tǒng)中提供了產(chǎn)品的類庫,且所有產(chǎn)品的接口相同時,要求客戶端類不依賴產(chǎn)品實(shí)例的創(chuàng)建細(xì)節(jié)和內(nèi)部結(jié)構(gòu)時,抽象工廠也適合這種情況
六、對比
抽象工廠模式和工廠方法模式對比
總體而言:
工廠模式中的每一個形態(tài)都是針對一定問題的解決方案,工廠方法針對的是多個產(chǎn)品系列結(jié)構(gòu)
抽象工廠模式針對的是多個產(chǎn)品族結(jié)構(gòu),一個產(chǎn)品族內(nèi)有多個產(chǎn)品系列。
七、總結(jié)
抽象工廠模式是為用戶端 提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,用戶端無需知道他們需要的產(chǎn)品怎么做的,它只需要調(diào)用接口方法就行。
抽象工廠模式,不僅可以實(shí)現(xiàn)多個接口,而且每個工廠也可以生產(chǎn)多種產(chǎn)品類,和工廠方法模式一樣,抽象工廠模式同樣實(shí)現(xiàn)了開發(fā)封閉原則。
注意:當(dāng)抽象工廠模式中的每個工廠類都只生產(chǎn)一種具體的產(chǎn)品時,這時候的抽象工廠模式相當(dāng)于工廠方法模式。
通過接口規(guī)定每個具體工廠需要實(shí)現(xiàn)的方法,不需要考慮具體產(chǎn)品如何生成,將生成具體產(chǎn)品的細(xì)節(jié)放到具體工廠中取實(shí)現(xiàn)。當(dāng)工廠生成產(chǎn)品需要更多的配置信息,將所有產(chǎn)品所需的配置信息都放在簡單工廠中太過雜亂,也不便于代碼維護(hù)。將生成某個產(chǎn)品的信息抽取出來,單獨(dú)放到一個類中,每個具體工廠對應(yīng)某個具體產(chǎn)品,使得具體工廠的職能更加單一,代碼簡潔。使信息局部化,降低了類的復(fù)雜性,變更引起的風(fēng)險(xiǎn)降低。