什么是工廠模式?工廠模式有哪些類型?如何使用它們?
工廠設(shè)計模式是一種創(chuàng)建對象的設(shè)計模式,它的主要目的是通過定義一個接口來創(chuàng)建對象,使得子類決定實例化哪個類。這篇文章,我們將分析工廠模式是什么,它包含什么類型以及如何工作。
從整體上看,工廠模式可以分為三種主要類型:簡單工廠模式、工廠方法模式和抽象工廠模式。
一、簡單工廠模式
1. 概述
簡單工廠模式并不是一個正式的設(shè)計模式,而是一個創(chuàng)建對象的簡單方法。在簡單工廠模式中,通常會有一個工廠類,它根據(jù)參數(shù)的不同返回不同類型的對象。這個模式的優(yōu)點是簡單明了,但缺點是違背了開閉原則。
2. 角色
- 工廠類:負(fù)責(zé)創(chuàng)建產(chǎn)品的實例,提供一個靜態(tài)方法供外部調(diào)用。
- 產(chǎn)品類:所有產(chǎn)品類都需實現(xiàn)相同的接口,用于定義產(chǎn)品的公共行為。
- 客戶端:通過工廠類來獲取產(chǎn)品實例,并使用這些實例。
3. 實現(xiàn)
下面我們通過一個簡單的示例代碼來展示是簡單工廠模式如何實現(xiàn):
// 產(chǎn)品接口
interface Product {
void use();
}
// 具體產(chǎn)品1
class ConcreteProduct1 implements Product {
public void use() {
System.out.println("產(chǎn)品1");
}
}
// 具體產(chǎn)品2
class ConcreteProduct2 implements Product {
public void use() {
System.out.println("產(chǎn)品2");
}
}
// 簡單工廠類,此處可以根據(jù)類型返回對應(yīng)的對象,但缺點是違背了開閉原則
class SimpleFactory {
public static Product createProduct(String type) {
switch (type) {
case "1":
return new ConcreteProduct1();
case "2":
return new ConcreteProduct2();
default:
return null;
}
}
}
// 客戶端
public class Client {
public static void main(String[] args) {
Product productA = SimpleFactory.createProduct("1");
productA.use();
Product productB = SimpleFactory.createProduct("2");
productB.use();
}
}
代碼分析:
- 產(chǎn)品接口 (Product) : 所有產(chǎn)品類必須實現(xiàn)這個接口,定義產(chǎn)品的公共行為(這里是 use() 方法)。
- 具體產(chǎn)品 (ConcreteProduct1, ConcreteProduct2) : 實現(xiàn)了 Product 接口,提供實際的產(chǎn)品功能。
- 工廠類 (SimpleFactory) : 通過 createProduct 方法,根據(jù)傳入的類型參數(shù)返回具體的產(chǎn)品實例。這個方法硬編碼了對產(chǎn)品類型的判斷,這直接使得 SimpleFactory 依賴于具體的產(chǎn)品類。
- 客戶端 (Client) : 用戶使用 SimpleFactory 來創(chuàng)造產(chǎn)品,并調(diào)用其方法。客戶端只需了解產(chǎn)品接口而不需要關(guān)心產(chǎn)品的具體實現(xiàn)。
在上述示例代碼中,SimpleFactory類是一個簡單工廠類,它可以根據(jù)類型返回相應(yīng)的對象,這是在日常開發(fā)中很多程序員容易編寫的代碼,但是,簡單工廠類違背了開閉原則。
4. 優(yōu)缺點
優(yōu)點:
- 簡單明了,易于理解和實現(xiàn)。
- 適合產(chǎn)品較少、變化不大的場景。
缺點:
- 一旦需要增加新的產(chǎn)品,工廠類就必須修改,不符合開閉原則。
- 工廠類的職責(zé)過于集中,增加了其復(fù)雜性。
二、工廠方法模式
1.. 概述
工廠方法模式是一種定義一個創(chuàng)建對象的接口,但由子類來決定要實例化的類,通過這種方式,工廠方法模式避免了簡單工廠模式所帶來的擴展問題,并遵循了開閉原則。
2. 角色
- 抽象工廠(Creator):聲明工廠方法,返回一個產(chǎn)品。
- 具體工廠(Concrete Creator):實現(xiàn)工廠方法,返回具體產(chǎn)品的實例。
- 抽象產(chǎn)品(Product):定義產(chǎn)品的公共接口。
- 具體產(chǎn)品(Concrete Product):實現(xiàn)抽象產(chǎn)品的具體類。
3. 實現(xiàn)
下面我們通過一個示例代碼來展示工廠方法模式的實現(xiàn):
// 抽象產(chǎn)品
interface Product {
void use();
}
// 具體產(chǎn)品A
class ConcreteProductA implements Product {
public void use() {
System.out.println("使用產(chǎn)品A");
}
}
// 具體產(chǎn)品B
class ConcreteProductB implements Product {
public void use() {
System.out.println("使用產(chǎn)品B");
}
}
// 抽象工廠
abstract class Creator {
public abstract Product factoryMethod();
}
// 具體工廠A
class ConcreteCreatorA extends Creator {
public Product factoryMethod() {
return new ConcreteProductA();
}
}
// 具體工廠B
class ConcreteCreatorB extends Creator {
public Product factoryMethod() {
return new ConcreteProductB();
}
}
// 客戶端
public class Client {
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
Product productA = creatorA.factoryMethod();
productA.use();
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.factoryMethod();
productB.use();
}
}
代碼分析:
- 抽象產(chǎn)品 (Product) : 與簡單工廠模式類似,定義了產(chǎn)品的公共接口。
- 具體產(chǎn)品 (ConcreteProductA, ConcreteProductB) : 實現(xiàn) Product 接口,提供具體的產(chǎn)品實現(xiàn)。
- 抽象工廠 (Creator) : 定義了一個工廠方法 factoryMethod(),這個方法將由具體工廠實現(xiàn),以返回具體產(chǎn)品。
- 具體工廠 (ConcreteCreatorA, ConcreteCreatorB) : 繼承自抽象工廠,實現(xiàn) factoryMethod(),返回相應(yīng)的具體產(chǎn)品實例。
- 客戶端 (Client) : 通過具體工廠類創(chuàng)建產(chǎn)品,從而減少了與產(chǎn)品創(chuàng)建過程的耦合。
工廠方法模式的設(shè)計使得增加新產(chǎn)品時,只需新增相應(yīng)的具體工廠類,符合開閉原則,增強了代碼的可維護性。
4. 優(yōu)缺點
優(yōu)點:
- 遵循開閉原則,可以很方便地擴展新的產(chǎn)品。
- 每個具體工廠只需關(guān)心自己創(chuàng)建的產(chǎn)品,減少了耦合。
缺點:
- 需要創(chuàng)建多個具體工廠,增加了系統(tǒng)復(fù)雜性。
- 客戶端需要了解具體工廠的參數(shù),不夠靈活。
三、抽象工廠模式
1. 概述
抽象工廠模式是為了解決工廠方法模式所無法處理的多個產(chǎn)品族的問題。抽象工廠提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們的具體類。通過抽象工廠模式,可以更方便地創(chuàng)建多個產(chǎn)品族的對象。
2.. 角色
- 抽象工廠(Abstract Factory):聲明創(chuàng)建抽象產(chǎn)品的接口。
- 具體工廠(Concrete Factory):實現(xiàn)抽象工廠的接口,創(chuàng)建具體產(chǎn)品。
- 抽象產(chǎn)品(Abstract Product):聲明具體相關(guān)產(chǎn)品的接口。
- 具體產(chǎn)品(Concrete Product):實現(xiàn)抽象產(chǎn)品的具體類。
3. 實現(xiàn)
下面我們通過一個簡單的示例代碼來展示是抽象工廠模式如何實現(xiàn):
// 抽象產(chǎn)品A
interface ProductA {
void use();
}
// 抽象產(chǎn)品B
interface ProductB {
void use();
}
// 具體產(chǎn)品A1
class ProductA1 implements ProductA {
public void use() {
System.out.println("使用產(chǎn)品A1");
}
}
// 具體產(chǎn)品A2
class ProductA2 implements ProductA {
public void use() {
System.out.println("使用產(chǎn)品A2");
}
}
// 具體產(chǎn)品B1
class ProductB1 implements ProductB {
public void use() {
System.out.println("使用產(chǎn)品B1");
}
}
// 具體產(chǎn)品B2
class ProductB2 implements ProductB {
public void use() {
System.out.println("使用產(chǎn)品B2");
}
}
// 抽象工廠
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具體工廠1
class ConcreteFactory1 implements AbstractFactory {
public ProductA createProductA() {
return new ProductA1();
}
public ProductB createProductB() {
return new ProductB1();
}
}
// 具體工廠2
class ConcreteFactory2 implements AbstractFactory {
public ProductA createProductA() {
return new ProductA2();
}
public ProductB createProductB() {
return new ProductB2();
}
}
// 客戶端
public class Client {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
ProductB productB1 = factory1.createProductB();
productA1.use();
productB1.use();
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB();
productA2.use();
productB2.use();
}
}
代碼分析:
- 抽象產(chǎn)品 (ProductA, ProductB) : 定義了兩類產(chǎn)品的公共接口,可以分別實現(xiàn)不同的具體產(chǎn)品。
- 具體產(chǎn)品 (ProductA1, ProductA2, ProductB1, ProductB2) : 實現(xiàn)各自的接口,表示具體的產(chǎn)品。
- 抽象工廠 (AbstractFactory) : 定義創(chuàng)建產(chǎn)品 A 和產(chǎn)品 B 的方法。不同的具體工廠會實現(xiàn)這些方法,返回相應(yīng)的產(chǎn)品。
- 具體工廠 (ConcreteFactory1, ConcreteFactory2) : 實現(xiàn)抽象工廠的方法,生產(chǎn)具體的產(chǎn)品。比如 ConcreteFactory1 生產(chǎn) ConcreteProductA1 和 ConcreteProductB1。
- 客戶端 (Client) : 客戶端通過抽象工廠來創(chuàng)建產(chǎn)品,而不直接依賴于具體的產(chǎn)品類,從而實現(xiàn)了與具體產(chǎn)品的解耦。
抽象工廠模式適合于需要創(chuàng)建多種產(chǎn)品家族的場合,客戶端可以通過改變工廠來實現(xiàn)不同產(chǎn)品組的創(chuàng)建,減少了對具體產(chǎn)品類的依賴。引入抽象工廠模式可以減少耦合,提升系統(tǒng)的靈活性。
4. 優(yōu)缺點
優(yōu)點:
- 可以創(chuàng)建相關(guān)或相互依賴的對象,減少耦合。
- 遵循開閉原則,增加新的產(chǎn)品族時,無需修改已有代碼。
缺點:
- 增加了系統(tǒng)的復(fù)雜性。需要有一個完整的產(chǎn)品族。
- 隨著產(chǎn)品的增加,工廠類會變得臃腫。
四、使用場景
工廠模式的使用場景主要包括以下幾個方面:
- 對象創(chuàng)建過程復(fù)雜:當(dāng)對象的創(chuàng)建過程涉及很多步驟或者復(fù)雜的邏輯時,使用工廠模式可以將這個邏輯封裝在工廠中。
- 希望將創(chuàng)建對象的細節(jié)與使用對象的代碼分離:工廠模式可以將對象的創(chuàng)建與使用解耦,進而提高代碼的可維護性和可擴展性。
- 系統(tǒng)需要獨立于產(chǎn)品的創(chuàng)建、組合和表示:當(dāng)一個系統(tǒng)應(yīng)該獨立于其產(chǎn)品的創(chuàng)建、組件和組織時,可以使用工廠模式來隔離這些過程。
五、使用工廠模式的框架
工廠模式在 Java領(lǐng)域有著廣泛的使用,這里列舉了幾個常見框架:
1. Spring Framework
Spring框架是一個非常典型的使用工廠模式的例子。Spring使用工廠模式來創(chuàng)建和管理對象。以下是幾個具體的實現(xiàn):
- BeanFactory:Spring的核心工廠接口,用于管理和創(chuàng)建Beans。BeanFactory接口提供了獲取Bean的統(tǒng)一方法。
- ApplicationContext:ApplicationContext是BeanFactory的一個子接口,提供了更加豐富的功能,如國際化、事件傳播等。它的實現(xiàn)類(例如ClassPathXmlApplicationContext、AnnotationConfigApplicationContext)充當(dāng)特定的工廠,實現(xiàn)了不同的獲取Bean方式。
2. Hibernate
Hibernate是一個廣泛使用的ORM框架,它在配置和創(chuàng)建SessionFactory時使用了工廠模式。
- SessionFactory:Hibernate通過SessionFactory接口的實現(xiàn)類(如Configuration類)來建立與數(shù)據(jù)庫的連接。開發(fā)者可以通過工廠方法獲取Session對象,通過Session與數(shù)據(jù)庫進行交互。
3. JPA
JPA (Java Persistence API)是Java的持久化標(biāo)準(zhǔn),許多JPA實現(xiàn)(例如Hibernate, EclipseLink)也利用工廠模式來創(chuàng)建實體管理器(EntityManager)。
- EntityManagerFactory:通過EntityManagerFactory的實現(xiàn),應(yīng)用程序可以創(chuàng)建EntityManager對象,從而與數(shù)據(jù)庫進行操作。這種設(shè)計使得具體的實現(xiàn)可以更換而不影響客戶端代碼。
4. Apache
在 Apache的 Apache Commons 和 Apache POI也使用了工廠模式:
- Apache Commons:在Apache Commons庫中,有許多獲取對象的靜態(tài)工廠方法,特別是在創(chuàng)建工具類時。
- Apache POI:在處理Excel文件時,它使用工廠模式來創(chuàng)建不同類型的Workbook對象(例如,HSSFWorkbook和XSSFWorkbook),具體取決于文件格式。
六、小結(jié)
本文,我們詳細地分析工廠模式以及使用示例代碼進行實現(xiàn),工廠設(shè)計模式提供了一種靈活的方式來創(chuàng)建對象,根據(jù)不同的需求,選擇適當(dāng)?shù)墓S模式可以有效地提高代碼的可維護性和可擴展性。在實際開發(fā)中,我們應(yīng)該根據(jù)具體問題選擇合適的設(shè)計模式,從而提高軟件的質(zhì)量和開發(fā)效率。