?作者:貓十二懿
?????賬號:CSDN 、掘金 、個人博客 、Github
??公眾號:貓十二懿
抽象工廠模式
1、抽象工廠模式介紹
抽象工廠模式(Abstract Factory Pattern)是一種創(chuàng)建型設(shè)計模式,圍繞一個超級工廠創(chuàng)建其他工廠,也稱作為工廠的工廠(大工廠里的小工廠)。在抽象工廠模式中,接口負(fù)責(zé)創(chuàng)建一組相關(guān)對象的工廠,而不需要顯式指定它們的類。這種設(shè)計模式能夠?qū)?mark>客戶端與具體的實現(xiàn)分離,從而使得客戶端可以在不必知道具體產(chǎn)品的情況下創(chuàng)建多個相關(guān)的產(chǎn)品對象。
1.1 抽象工廠的結(jié)構(gòu)圖
抽象工廠模式(Abstract Factory),提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無須指定它們具體的類。
- AbstractFactory:抽象工廠類,定義了一組用于創(chuàng)建產(chǎn)品(ProductA和ProductB)的抽象方法,具體的工廠類將實現(xiàn)這些抽象方法。
- ConcreteFactory1和ConcreteFactory2:具體工廠類,實現(xiàn)了AbstractFactory中定義的創(chuàng)建產(chǎn)品的抽象方法。在本例中,ConcreteFactory1用于創(chuàng)建ProductA1和ProductB1的實例,而ConcreteFactory2用于創(chuàng)建ProductA2和ProductB2的實例。
- AbstractProductA和AbstractProductB:抽象產(chǎn)品類,定義了產(chǎn)品的通用接口。具體產(chǎn)品類將實現(xiàn)這些接口。
- ProductA1、ProductA2、ProductB1和ProductB2:具體產(chǎn)品類,實現(xiàn)了AbstractProductA和AbstractProductB中定義的接口。
當(dāng)客戶端需要創(chuàng)建產(chǎn)品時,它會先創(chuàng)建一個具體的工廠類,然后使用該工廠類創(chuàng)建所需的產(chǎn)品實例。由于抽象工廠提供了一組相關(guān)的產(chǎn)品接口,因此這些產(chǎn)品之間具有共同點,可以很方便地進行組合、配對或者交換。而具體工廠則根據(jù)客戶端的需求,在運行時動態(tài)創(chuàng)建產(chǎn)品實例,從而實現(xiàn)了客戶端與具體實現(xiàn)之間的解耦。
那下面來看看這個具體的實現(xiàn)吧
1.2 抽象工廠模板實現(xiàn)
抽象產(chǎn)品類:
// 抽象產(chǎn)品類 A
interface AbstractProductA {
void operationA();
}
// 抽象產(chǎn)品類 B
interface AbstractProductB {
void operationB();
}
實現(xiàn)不同的抽象產(chǎn)品,產(chǎn)出具體不同的產(chǎn)品:
// 具體產(chǎn)品類 A1
class ProductA1 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("具體產(chǎn)品類 A1 實現(xiàn)抽象產(chǎn)品 A");
}
}
// 具體產(chǎn)品類 A2
class ProductA2 implements AbstractProductA {
@Override
public void operationA() {
System.out.println("具體產(chǎn)品類 A2 實現(xiàn)抽象產(chǎn)品 A");
}
}
// 具體產(chǎn)品類 B1
class ProductB1 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("具體產(chǎn)品類 B1 實現(xiàn)抽象產(chǎn)品 B");
}
}
// 具體產(chǎn)品類 B2
class ProductB2 implements AbstractProductB {
@Override
public void operationB() {
System.out.println("具體產(chǎn)品類 B2 實現(xiàn)抽象產(chǎn)品 B");
}
}
抽象工廠類:創(chuàng)建產(chǎn)品的類
相當(dāng)于一個大工廠,里面可以產(chǎn)出很多產(chǎn)品,但是每個產(chǎn)品都屬于大工廠里面的一個小工廠,也就是大工廠里面有小工廠,在小工廠里面實現(xiàn)具體的產(chǎn)品
// 抽象工廠類
interface AbstractFactory {
AbstractProductA createProductA();
AbstractProductB createProductB();
}
具體的小工廠:
// 具體工廠類 1
class ConcreteFactory1 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ProductB1();
}
}
// 具體工廠類 2
class ConcreteFactory2 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ProductB2();
}
}
客戶端實現(xiàn):
// 客戶端
public class Client {
public static void main(String[] args) {
// 創(chuàng)建具體工廠類 1
AbstractFactory factory1 = new ConcreteFactory1();
// 使用工廠類 1 創(chuàng)建產(chǎn)品 A 和 B
AbstractProductA productA1 = factory1.createProductA();
AbstractProductB productB1 = factory1.createProductB();
// 調(diào)用產(chǎn)品 A 和 B 的方法
productA1.operationA();
productB1.operationB();
// 創(chuàng)建具體工廠類 2
AbstractFactory factory2 = new ConcreteFactory2();
// 使用工廠類 2 創(chuàng)建產(chǎn)品 A 和 B
AbstractProductA productA2 = factory2.createProductA();
AbstractProductB productB2 = factory2.createProductB();
// 調(diào)用產(chǎn)品 A 和 B 的方法
productA2.operationA();
productB2.operationB();
}
}
2、具體例子實現(xiàn)
假設(shè)你是一位室內(nèi)設(shè)計師,你需要為客戶的房間設(shè)計家具。不同的客戶有不同的風(fēng)格和預(yù)算,因此你需要選擇不同的家具制造商來滿足客戶的需求。在這種情況下,你可以將抽象工廠模式應(yīng)用于家具制造業(yè)。
首先,你需要定義一個家具抽象工廠接口,它有兩個方法:
createChair()
和createSofa()
,分別用于創(chuàng)建椅子和沙發(fā)。然后,你可以創(chuàng)建多個具體的家具工廠類(例如,現(xiàn)代家具工廠、傳統(tǒng)家具工廠等),它們分別實現(xiàn)了家具抽象工廠接口并負(fù)責(zé)創(chuàng)建不同類型的家具。最后,你可以根據(jù)客戶的需求選擇相應(yīng)的家具工廠來創(chuàng)建家具。例如,如果客戶需要現(xiàn)代家具,你可以使用現(xiàn)代家具工廠來創(chuàng)建現(xiàn)代風(fēng)格的椅子和沙發(fā);如果客戶需要傳統(tǒng)家具,你可以使用傳統(tǒng)家具工廠來創(chuàng)建傳統(tǒng)風(fēng)格的椅子和沙發(fā)。
這樣,抽象工廠模式幫助你解耦了客戶和具體的家具制造商,使得你可以更容易地切換不同的制造商,同時也為客戶提供了更多的選擇。
2.1 不使用抽象工廠模式實現(xiàn)
家具類:
/**
* @author Shier
* 家具類
*/
public class Furniture {
private String type;
private String style;
private double price;
public Furniture(String type, String style, double price) {
this.type = type;
this.style = style;
this.price = price;
}
public void printInfo() {
System.out.println("Type: " + type);
System.out.println("Style: " + style);
System.out.println("Price: " + price);
}
}
現(xiàn)代風(fēng)格類:
/**
* @author Shier
* 現(xiàn)代風(fēng)格家具制造商
*/
public class ModernFurnitureMaker {
public Furniture createChair() {
return new Furniture("椅子", "現(xiàn)代風(fēng)格", 150.0);
}
public Furniture createSofa() {
return new Furniture("沙發(fā)", "現(xiàn)代風(fēng)格", 500.0);
}
}
傳統(tǒng)風(fēng)格類:
/**
* @author Shier
* 傳統(tǒng)風(fēng)格家具制造商
*/
public class TraditionalFurnitureMaker {
public Furniture createChair() {
return new Furniture("椅子", "傳統(tǒng)風(fēng)格", 100.0);
}
public Furniture createSofa() {
return new Furniture("沙發(fā)", "傳統(tǒng)風(fēng)格", 600.0);
}
}
客戶端類:
/**
* @author Shier
* 客戶端類
*/
public class Client {
public static void main(String[] args) {
// 創(chuàng)建現(xiàn)代風(fēng)格家具
ModernFurnitureMaker modernMaker = new ModernFurnitureMaker();
Furniture modernChair = modernMaker.createChair();
Furniture modernSofa = modernMaker.createSofa();
// 打印信息
modernChair.printInfo();
modernSofa.printInfo();
// 創(chuàng)建傳統(tǒng)風(fēng)格家具
TraditionalFurnitureMaker traditionalMaker = new TraditionalFurnitureMaker();
Furniture traditionalChair = traditionalMaker.createChair();
Furniture traditionalSofa = traditionalMaker.createSofa();
// 打印信息
traditionalChair.printInfo();
traditionalSofa.printInfo();
}
}
這個示例中,我們創(chuàng)建了兩個類來分別表示現(xiàn)代風(fēng)格和傳統(tǒng)風(fēng)格的家具制造商。每個家具制造商都有自己的 createChair()
和 createSofa()
方法來創(chuàng)建相應(yīng)類型的家具對象。
在客戶端代碼中,我們創(chuàng)建了具體的家具制造商對象(即 ModernFurnitureMaker
和 TraditionalFurnitureMaker
),并使用它們來創(chuàng)建家具對象。然后我們打印了每個家具對象的信息。
雖然這個示例沒有使用抽象工廠模式,但是它依然可以滿足基本的需求。但是當(dāng)需要制作的家里越多時,就會出現(xiàn)越來越多重復(fù)的代碼。
不使用抽象工廠模式的不好之處可能包括:
- 不易于擴展:如果要添加新的產(chǎn)品類型,就需要修改所有創(chuàng)建產(chǎn)品的代碼。這種修改可能會涉及多個類,不容易維護。
- 與具體產(chǎn)品實現(xiàn)綁定:客戶端直接依賴具體的產(chǎn)品實現(xiàn),而不是一個接口或抽象類。這使得客戶端代碼和具體產(chǎn)品實現(xiàn)緊密綁定在一起,難以進行替換或測試。(耦合度高)
- 可能導(dǎo)致代碼重復(fù):如果多個客戶端需要創(chuàng)建相同類型的產(chǎn)品,就需要在每個客戶端中復(fù)制相同的創(chuàng)建代碼。這種代碼重復(fù)可能會增加維護成本,并且容易出現(xiàn)錯誤。
2.2 使用抽象工廠模式實現(xiàn)
抽象產(chǎn)品類:
/**
* 抽象產(chǎn)品類-椅子
*/
public interface Chair {
void printInfo();
}
/**
* 抽象產(chǎn)品類-沙發(fā)
*/
public interface Sofa {
void printInfo();
}
具體產(chǎn)品類:
/**
* @author Shier
* 具體產(chǎn)品類-現(xiàn)代椅子
*/
public class ModernChair implements Chair {
public void printInfo() {
System.out.println("類型: 椅子, 風(fēng)格: 現(xiàn)代, 價格: 150.0");
}
}
/**
* @author Shier
* 具體產(chǎn)品類-現(xiàn)代沙發(fā)
*/
public class ModernSofa implements Sofa {
public void printInfo() {
System.out.println("類型: 沙發(fā), 風(fēng)格: 現(xiàn)代, 價格: 500.0");
}
}
/**
* @author Shier
* 具體產(chǎn)品類-傳統(tǒng)椅子
*/
public class TraditionalChair implements Chair {
public void printInfo() {
System.out.println("類型: 椅子, 風(fēng)格: 傳統(tǒng), 價格: 100.0");
}
}
/**
* @author Shier
* 具體產(chǎn)品類-傳統(tǒng)沙發(fā)
*/
public class TraditionalSofa implements Sofa {
public void printInfo() {
System.out.println("類型: 沙發(fā), 風(fēng)格: 傳統(tǒng), 價格: 600.0");
}
}
具體產(chǎn)品工廠類:
/**
* @author Shier
* 具體工廠類-現(xiàn)代風(fēng)格家具
*/
public class ModernFurnitureFactory implements FurnitureMaker {
public Chair createChair() {
return new ModernChair();
}
public Sofa createSofa() {
return new ModernSofa();
}
}
/**
* @author Shier
* 具體工廠類-傳統(tǒng)風(fēng)格家具
*/
public class TraditionalFurnitureFactory implements FurnitureMaker {
public Chair createChair() {
return new TraditionalChair();
}
public Sofa createSofa() {
return new TraditionalSofa();
}
}
客戶端類:
/**
* @author Shier
* 客戶端
*/
public class Client {
public static void main(String[] args) {
// 創(chuàng)建現(xiàn)代風(fēng)格家具工廠
FurnitureMaker modernFactory = new ModernFurnitureFactory();
Chair modernChair = modernFactory.createChair();
Sofa modernSofa = modernFactory.createSofa();
// 打印信息
modernChair.printInfo();
modernSofa.printInfo();
// 創(chuàng)建傳統(tǒng)風(fēng)格家具工廠
FurnitureMaker traditionalFactory = new TraditionalFurnitureFactory();
Chair traditionalChair = traditionalFactory.createChair();
Sofa traditionalSofa = traditionalFactory.createSofa();
// 打印信息
traditionalChair.printInfo();
traditionalSofa.printInfo();
}
}
我們首先創(chuàng)建了
Chair
和Sofa
兩個抽象產(chǎn)品類,代表不同類型的家具。然后,我們創(chuàng)建了每個具體產(chǎn)品類來實現(xiàn)相應(yīng)的產(chǎn)品。接下來,我們創(chuàng)建了
FurnitureMaker
抽象工廠類,其中包含了createChair()
和createSofa()
兩個抽象方法。每個具體工廠類都需要實現(xiàn)這些方法來創(chuàng)建相應(yīng)類型的家具對象。在客戶端代碼中,我們創(chuàng)建了具體的家具制造商對象(即
ModernFurnitureFactory
和TraditionalFurnitureFactory
),并使用它們來創(chuàng)建家具對象。然后我們打印了每個家具對象的信息。雖然看上去比不使用抽象工廠方法創(chuàng)建了更多的類,但是通過使用抽象工廠模式,我們可以將產(chǎn)品的創(chuàng)建與具體產(chǎn)品實現(xiàn)分離,并且可以方便地添加新的產(chǎn)品類型或修改現(xiàn)有的產(chǎn)品實現(xiàn),而無需修改客戶端代碼。
3、抽象工廠模式總結(jié)
抽象工廠模式的優(yōu)點:
- 可以確??蛻舳耸褂玫氖峭活惍a(chǎn)品對象,從而避免了不同的產(chǎn)品之間的兼容性問題。
- 在一個應(yīng)用中只需要在初始化的時候出 現(xiàn)一次,這就使得改變一個應(yīng)用的具體工廠變得非常容易,它只需要改變具體工廠即可使用不同的產(chǎn)品配置。
- 隱藏了具體產(chǎn)品的實現(xiàn),從而使客戶端代碼與具體產(chǎn)品實現(xiàn)分離,增強了可擴展性和靈活性。讓具體的創(chuàng)建實例過程與客戶端分離,客戶端是通過它們的抽象接口操縱實例,產(chǎn)品的具體類名也被具體工廠的實現(xiàn)分離,不會出現(xiàn)在客戶代碼中。
- 系統(tǒng)更易于擴展,因為增加新的具體工廠和產(chǎn)品族很容易,無需修改原有代碼。
抽象工廠模式的缺點:
- 當(dāng)需要添加新的產(chǎn)品族時,需要修改抽象工廠的接口,這將導(dǎo)致所有具體工廠都需要進行修改,系統(tǒng)變得不穩(wěn)定。
- 當(dāng)需要添加新的產(chǎn)品對象時,除了添加新的具體產(chǎn)品類外,還需要修改抽象工廠接口和所有具體工廠類,這將導(dǎo)致系統(tǒng)的維護成本增加。
- 在增加抽象層的同時,也增加了系統(tǒng)的復(fù)雜度和理解難度。
抽象工廠模式適用于以下情況:
- 系統(tǒng)需要一組相關(guān)或相互依賴的對象,而這些對象通常具有共同的接口。
- 系統(tǒng)不關(guān)心具體產(chǎn)品如何創(chuàng)建、實現(xiàn)等細(xì)節(jié),只關(guān)心產(chǎn)品的規(guī)格和功能。
- 系統(tǒng)中有多個產(chǎn)品族,每個產(chǎn)品族都有一些共同的約束條件,這些約束條件不是通過類的繼承關(guān)系來實現(xiàn)的。
常見的應(yīng)用場景包括:文章來源地址http://www.zghlxwxcb.cn/news/detail-467237.html
- 用戶界面工具包:例如需要創(chuàng)建不同風(fēng)格(如 Windows、Mac OS、Linux 等)下的按鈕、文本框等界面組件,可以使用抽象工廠模式來為每個風(fēng)格創(chuàng)建一個工廠,工廠可以創(chuàng)建所需的所有組件。
- 數(shù)據(jù)訪問庫:例如需要為 Oracle、MySQL、SQL Server 等不同數(shù)據(jù)庫提供數(shù)據(jù)訪問對象,可以使用抽象工廠模式為每個數(shù)據(jù)庫創(chuàng)建一個工廠,工廠可以創(chuàng)建所需的連接、命令等對象。(在《大話設(shè)計模式》就是拿這個例子來說明抽象工廠模式的)
- 醫(yī)療設(shè)備控制系統(tǒng):例如需要控制不同型號的醫(yī)療器械(如心電圖儀、血壓計、藥品泵等),每個型號的設(shè)備都有自己的控制協(xié)議,可以使用抽象工廠模式為每個設(shè)備型號創(chuàng)建一個工廠,工廠可以創(chuàng)建控制該型號設(shè)備的對象。
系統(tǒng)不關(guān)心具體產(chǎn)品如何創(chuàng)建、實現(xiàn)等細(xì)節(jié),只關(guān)心產(chǎn)品的規(guī)格和功能。
3. 系統(tǒng)中有多個產(chǎn)品族,每個產(chǎn)品族都有一些共同的約束條件,這些約束條件不是通過類的繼承關(guān)系來實現(xiàn)的。文章來源:http://www.zghlxwxcb.cn/news/detail-467237.html
常見的應(yīng)用場景包括:
- 用戶界面工具包:例如需要創(chuàng)建不同風(fēng)格(如 Windows、Mac OS、Linux 等)下的按鈕、文本框等界面組件,可以使用抽象工廠模式來為每個風(fēng)格創(chuàng)建一個工廠,工廠可以創(chuàng)建所需的所有組件。
- 數(shù)據(jù)訪問庫:例如需要為 Oracle、MySQL、SQL Server 等不同數(shù)據(jù)庫提供數(shù)據(jù)訪問對象,可以使用抽象工廠模式為每個數(shù)據(jù)庫創(chuàng)建一個工廠,工廠可以創(chuàng)建所需的連接、命令等對象。(在《大話設(shè)計模式》就是拿這個例子來說明抽象工廠模式的)
- 醫(yī)療設(shè)備控制系統(tǒng):例如需要控制不同型號的醫(yī)療器械(如心電圖儀、血壓計、藥品泵等),每個型號的設(shè)備都有自己的控制協(xié)議,可以使用抽象工廠模式為每個設(shè)備型號創(chuàng)建一個工廠,工廠可以創(chuàng)建控制該型號設(shè)備的對象。
到了這里,關(guān)于創(chuàng)建型設(shè)計模式05-抽象工廠模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!