設計模式 - 簡單工廠、工廠模式

簡單工廠

前言


如何輕鬆方便的構造對象實例,而不必關心對象實例的細> 節和複雜的過程呢?

上面這句是工廠模式所關注的問題,這樣說有點抽象,用個情境來說:

現在飲料店來了一個顧客,他想要點紅茶跟綠茶,用UML圖表示,長的像這樣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Customer : MonoBehaviour {

private void Start()
{
GreenTea greenTea = new GreenTea();
AddMaterial(); //加料
Blend(); //混合
Cup(); //裝杯

BlackTea blackTea = new BlackTea();
AddMaterial(); //加料
Blend(); //混合
Cup(); //裝杯
}
}

但這樣顧客就需要知道綠茶的製造流程 ( 加料、混合、裝杯) 這不是很奇怪嗎,為什麼顧客需要知道你加什麼料啦!用程式的角度來說,就是顧客就跟製造的飲料緊密的耦合在一起。
以後越來越多品項的話,在顧客那就需要知道更多製作方法,這樣顧客都可以開店了呢! 於是為了解決這個問題,就會使用到這次的主題 — 簡單工廠。

具體實現

具體的創建過程由內部進行,顧客只要把想喝什麼丟進去這個工廠就可以了。

現在將茶抽象出來,因為綠茶跟紅茶都是茶,而且它們都經過三步驟 - 加料、混合、裝杯,所以將他們繼承至茶類

1
2
3
public abstract class Tea { }
public class BlackTea : Tea { }
public class GreenTea : Tea { }

再來實作一個工廠,裡面有可以讓外部點茶的方法 - OrderTea,傳入想要點的茶的名字。

1
2
3
4
5
6
7
8
9
10
11
public class TeaFactory
{
public Tea OrderTea(string name)
{
if (name == "GreenTea")
return new GreenTea();
else if (name == "BlackTea")
return new BlackTea();
else return null;
}
}

這樣在顧客那,就可以使用茶工廠的OrderTea傳入想要點的茶來拿到茶了,與之前不一樣的是
這樣顧客不需要知道這杯茶是怎麼做的,只需要知道茶的名字就可以得到想要的茶,實作都會在茶工廠內部實作。

1
2
3
4
5
6
7
8
9
public class Customer : MonoBehaviour {

private void Start()
{
TeaFactory teaFactory = new TeaFactory();
Tea greenTea = teaFactory.OrderTea("GreenTea");
Tea blackTea = teaFactory.OrderTea("BlackTea");
}
}

但是!! 簡單工廠並不符合設計模式的開閉原則,每次修改的時候就得在原始代碼上新增對應,這樣一旦東西多了,不止每次修改都有風險出Bug,而且程式碼擠在一起也很難閱讀,因此這時候就需要使用到工廠模式啦

工廠模式


工廠方法模式的實質是「定義一個建立物件的介面,但讓實現這個介面的類來決定實體化哪個類。工廠方法讓類別的實體化推遲到子類別中進行。」

既然要符合開閉原則,那麼就把會修改原代碼的地方抽出來
上面看到TeaFactory的OrderTea方法是因為傳入的參數不同,導致每次新增品項都要修改原代碼一次
因此,把他抽出來做成介面

1
2
3
4
interface TeaFactory
{
Tea OrderTea();
}

原本的BlackTea跟GreenTea不變,額外再做一個GreenTeaFactory、BlackTeaFactory專門賣這兩種茶
這樣以後如果多了MikeTea,就再將MikeTea繼承於Tea,然後實作一個MikeTeaFactory繼承TeaFactory就好了,不需要改變到原始的代碼,就符合開閉原則了
但這缺點就是,如果新增一個MilkTea就要做一個MilkTeaFactory來對應,這樣每次新增就會跑出兩個類別要實作。

現在實作上面說的東西:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class BlackTeaFactory : TeaFactory
{
public Tea OrderTea()
{
return new BlackTea();
}
}

public class GreenTeaFactory : TeaFactory
{
public Tea OrderTea()
{
return new GreenTea();
}
}

顧客:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Customer : MonoBehaviour {

private void Start()
{

//工廠方法
BlackTeaFactory blackTeaFactory = new BlackTeaFactory();
blackTeaFactory.OrderTea();
GreenTeaFactory greenTeaFactory = new GreenTeaFactory();
greenTeaFactory.OrderTea();

}
}


而且這樣的方法又有一個問題了,那就是一個具體工廠只能創建一個產品
像是上面的綠茶工廠,就只會生產綠茶,紅茶工廠只會生產紅茶
實際過程中一個工廠往往需要生產多類產品,這時候為了解決這個問題,就需要用到抽象工廠了,見下一篇~