[design pattern] factory pattern:打造物件創建的萬能工具

工廠模式:物件創建的神奇魔法師

在軟體開發的世界裡,工廠模式(Factory Pattern)就像是一位多才多藝的魔法師,能夠根據不同的需求變出各種類型的物件。這個設計模式通過包裝物件的創建過程,為我們提供了一種既簡單又高效的方式來處理複雜的物件實例化邏輯。讓我們一起來認識這個厲害的設計模式吧!

1. 工廠模式的核心理念

工廠模式的核心思想其實很簡單,就像是:

  1. 把變化藏起來:將物件的創建過程藏在工廠類別中,讓使用者不需要知道太多細節。
  2. 讓使用更簡單:使用者只需要知道要什麼,不需要知道怎麼做。
  3. 集中管理:在一個地方統一管理物件的創建,方便修改和維護。
  4. 容易添加新功能:可以輕鬆地添加新的物件類型,不需要大改現有的程式碼。

2. 工廠模式的種類

工廠模式主要有三種類型:

  1. 簡單工廠(Simple Factory):就像是一個小型工作坊,用一個簡單的方法來創建物件。
  2. 工廠方法(Factory Method):像是一條生產線,可以生產不同類型的產品。
  3. 抽象工廠(Abstract Factory):像是一個大型工廠,可以同時生產多種相關的產品。

3. 工廠模式的實際應用場景

工廠模式在很多地方都能派上用場,例如:

  1. 支付系統:根據用戶選擇的支付方式(信用卡、PayPal、銀行轉帳等)創建對應的支付處理物件。
  2. 資料庫連線:根據設定創建不同類型的資料庫連線(MySQL、PostgreSQL、MongoDB等)。
  3. 使用者介面元件:根據使用者的主題設定創建不同風格的UI元件。
  4. 日誌系統:根據設定創建不同類型的日誌記錄器(檔案日誌、資料庫日誌、網路日誌等)。
  5. 跨平台應用開發:根據執行平台創建適合的系統服務物件。

4. 實際範例:工廠模式的實作

讓我們通過一個支付系統的例子來看看工廠模式是如何運作的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// 支付基礎類別
class Payment {
process(amount) {
throw new Error('process() 必須由子類別實作');
}
}

// 具體支付類別:信用卡支付
class CreditCardPayment extends Payment {
constructor({ cardNumber, cardHolder, expirationDate }) {
super();
this.cardNumber = cardNumber;
this.cardHolder = cardHolder;
this.expirationDate = expirationDate;
}

process(amount) {
return `正在處理 ${this.cardHolder} 的信用卡支付,金額為 ${amount}`;
}
}

// 具體支付類別:PayPal支付
class PayPalPayment extends Payment {
constructor({ email }) {
super();
this.email = email;
}

process(amount) {
return `正在處理 ${this.email} 的PayPal支付,金額為 ${amount}`;
}
}

// 支付工廠類別
class PaymentFactory {
constructor() {
this.paymentMethods = {
CreditCard: CreditCardPayment,
PayPal: PayPalPayment
};
}

createPayment(method, options) {
const PaymentMethod = this.paymentMethods[method];
if (!PaymentMethod) {
throw new Error('未知的支付方式');
}
return new PaymentMethod(options);
}

// 動態新增支付方式
addPaymentMethod(methodName, PaymentClass) {
this.paymentMethods[methodName] = PaymentClass;
}
}

// 使用範例
const factory = new PaymentFactory();

const creditCardPayment = factory.createPayment('CreditCard', {
cardNumber: '1234 5678 9012 3456',
cardHolder: '王小明',
expirationDate: '12/25'
});

console.log(creditCardPayment.process(100)); // 輸出: 正在處理 王小明 的信用卡支付,金額為 100

const paypalPayment = factory.createPayment('PayPal', { email: 'xiaoming@example.com' });
console.log(paypalPayment.process(50)); // 輸出: 正在處理 xiaoming@example.com 的PayPal支付,金額為 50

// 動態新增新的支付方式
class BitcoinPayment extends Payment {
constructor({ address }) {
super();
this.address = address;
}

process(amount) {
return `正在處理比特幣支付,金額為 ${amount},支付地址:${this.address}`;
}
}

factory.addPaymentMethod('Bitcoin', BitcoinPayment);

const bitcoinPayment = factory.createPayment('Bitcoin', { address: '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2' });
console.log(bitcoinPayment.process(200)); // 輸出: 正在處理比特幣支付,金額為 200,支付地址:1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2

這個例子展示了如何使用工廠模式創建不同類型的支付物件,以及如何動態新增支援新的支付方式。

5. 工廠模式的優缺點

優點

  1. 降低耦合度:使用者的程式碼不需要和具體的產品類別綁定在一起,更容易修改和維護。
  2. 容易擴展:可以輕鬆新增新的產品類別,不需要修改現有的使用者程式碼。
  3. 集中管理:將物件的創建邏輯集中在一處,方便統一管理和修改。
  4. 簡化使用:工廠封裝了複雜的創建邏輯,讓使用者的程式碼更簡單。

缺點

  1. 增加類別數量:引入工廠類別和產品層次結構,可能會讓系統變得更複雜。
  2. 可能違反開閉原則:如果經常需要新增新產品,可能需要修改工廠類別。
  3. 對簡單物件可能過度設計:如果只有一兩種簡單的物件,使用工廠模式可能有點小題大作。

6. 工廠模式的最佳實踐

  1. 使用設定檔:將產品類型和具體類別的對應關係存在設定檔中,這樣就可以在不修改程式碼的情況下新增新產品。
  2. 搭配單例模式:工廠類別通常只需要一個實例,可以使用單例模式來實作。
  3. 善用反射機制:在支援反射的程式語言中,可以使用反射來動態創建物件,讓系統更有彈性。
  4. 考慮使用依賴注入:在某些情況下,依賴注入可能比工廠模式更適合,特別是在使用依賴注入框架的大型專案中。

結論

工廠模式是一個既強大又靈活的設計模式,它通過包裝物件創建的過程,為我們提供了一種優雅的方式來處理複雜的實例化邏輯。在設計系統時,合理使用工廠模式可以大大提高程式碼的可維護性和擴展性。不過,也要注意不要過度使用,對於簡單的情況,直接使用建構函式可能更直接有效。

作為一個優秀的軟體工程師,掌握工廠模式及其變體,並能在適當的場景中靈活運用,將使你的程式碼更加健壯、靈活且易於維護。


[design pattern] factory pattern:打造物件創建的萬能工具
https://terryyaowork.github.io/designpattern/20240827/2464715971/
作者
Terry Yao
發布於
2024年8月27日
許可協議