總覺得找到想要的工作遙遙無期...XD
開始慌了吧哈哈哈哈哈
不過其實著急也沒用... 換個角度想我又沒有要養小孩之類的經濟壓力
只要養活自己的話,現在算是綽綽有餘了
只要在這段期間內能夠持續充實自己,就不算是在浪費時間了
更不用說有些工作根本學不到什麼實質的東西,又累得跟狗一樣做到懷疑人森
與期勉強自己去做那些工作,還是輕鬆又有目標的充實自己吧
又到了設計模式的時間
今天來介紹工廠模式,不過裡面又有細分成幾種
有簡單工廠、工廠方法以及抽象工廠三種
今天就拿... 披薩店來舉例好了
假設今天要開一間披薩店,可能會有很多種口味的披薩,那麼大概會想把披薩這東西獨立出來,因為它是可變動的部分
所以大概會變成這樣:
class PizzaStore {
public:
Pizza* orderPizza(string type) {
Pizza *pizza = nullptr;
if (type == "cheese") { // 根據type來決定要產生什麼樣的披薩
pizza = new cheesePizza();
else if (type == "clam") {
pizza = new clamPizza();
}
.....
pizza->prepare(); // 各種pizza內實作的各種方法
pizza->bake();
.....
return pizza;
}
}
這樣看起來挺合理的吧,直覺地想就會這麼設計
但如果要增加或減少pizza的種類,就必須要去修改上面紅字那段的內容
其實我們要修改的只是pizza的種類,我們希望不要動用到PizzaStore的內容
PizzaStore裡面可能也有賣飲料啊,賣炸雞啊,可能不單純賣披薩嘛
想個辦法把物件之間的關聯性區分開來
這就是簡單工廠的概念,我們加入一個簡單工廠的類別到PizzaStore裡面,特別來處理pizza這件事情:
class PizzaStore {
public:
SimplePizzaFactory* m_factory; // 簡單工廠
PizzaStore(SimplePizzaFactory* factory) {
m_factory = factory; // 在建構子中傳入工廠的形式
}
Pizza* orderPizza(string type) {
Pizza *pizza = m_factory->createPizza(type); // 利用工廠產生不同口味的披薩
pizza.prepare(); // 各種pizza內實作的各種方法
pizza.bake();
.....
return pizza;
}
}
這樣的話,所有跟披薩相關的東西(前面那段紅字)都包到披薩的簡單工廠裡面去了
之後要修改披薩的種類等等,只要修改工廠的內容就行了
而且在建立PizzaStore的時候也可以傳入不同的工廠
比如說美國的披薩工廠啊、英國的披薩工廠啊等等,又多了一些彈性
這就是簡單工廠,嚴格說起來不算是一個設計模式,比較像是一種習慣吧
把需要修改的地方獨立出來,大概就是這種概念
簡單工廠的方式是另外建立一個類別傳入PizzaStore裡面,要執行的時候在依照這個工廠去做事情
其實我們換個角度想,我們何不直接把他合起來呢
只要讓PizzaStore變成是一個抽象類別,然後把createPizza這件事讓他的子類別去繼承實作就可以了
就像以下這樣:
class PizzaStore {
public:
Pizza* orderPizza(string type) {
Pizza *pizza = createPizza(type); // 利用方法產生不同口味的披薩
pizza.prepare(); // 各種pizza內實作的各種方法
pizza.bake();
.....
return pizza;
}
virtual Pizza createPizza(string type) = 0; // 留給子類別去實作
}
然後子類別可能就長這樣:
class NYPizzaStore : PizzaStore { // 繼承PizzaStore
public:
Pizza* orderPizza(string type) {
Pizza *pizza = createPizza(type); // 利用方法產生不同口味的披薩
pizza.prepare(); // 各種pizza內實作的各種方法
pizza.bake();
.....
return pizza;
}
Pizza* createPizza(string type) {
if (type == "cheese") {
return new NYCheesePizza();
....
}
}
這種方式把簡單工廠包成一個抽象的方法,讓子類別去實作的方式,就是工廠方法模式
在orderPizza()內呼叫createPizza(),但createPizza()是由子類別實作的
所以在設計上,可能就會變成不同地區的PizzaStore去繼承PizzaStore這個抽象類別
然後搭配上不同種類的Pizza(分別去繼承Pizza這個抽象類別)
但這樣又會遇到一個問題
前面的方式披薩會搭配不同的PizzaStore,但在披薩本身的製作上是由披薩本身的實作來決定的,從這個角度看,披薩和工廠是分開設計的,這樣很好
但如果說想要把披薩店和披薩的關係拉近一點,比如說披薩的生產要搭配不同地區的原料之類的
這時候我們就可以在不同的PizzaStore送不同的原料去給披薩
但我們同時又不想讓PizzaStore和提供原料這件事情綁在一起
這時候我們可以把簡單工廠的概念帶過來用,在PizzaStore裡面新增一個member負責生產原料,就叫他原料工廠吧
這邊簡單寫的話,大概是這樣的概念:
class NYPizzaStore : PizzaStore {
public:
NYPizzaStore() {
m_IngredientFactory = new NYIngredientFactory(); // 依照地區有不同的原料工廠,這個工廠是繼承IngredientFactory這個抽象類別的
}
Pizza* createPizza(string type) {
Pizza *pizza = nullptr;
if (type == "cheese") {
pizza = new CheesePizza(m_IngredientFactory); // 把原料工廠傳到披薩內部
}
...
pizza->prepare(); // 這樣這些pizza的製作都可以依照原料工廠來決定原料
pizza->bake();
...
}
}
當然pizza的實作也會跟著改變,不過那些細節這邊就不談了
其實前面也有稍微提到一下這個觀念,只是現在這個工廠變成一個抽象類別,要靠子類別繼承他去決定裡面的行為
這個就是抽象工廠模式,由子類去實作抽象類別的函數,執行期的時候讓子類決定實作內容
其實這樣看下來,好像並不是很複雜
只是利用繼承和合成的威力,把不同物件之間的關係鬆綁和連結這樣
不過其實設計模式就是這樣,讓程式的可讀性和擴展性更增加了
好啦這篇就這樣了~ 寫一寫突然變得比較清楚了XD
不然去面試都被問倒... 也是亂慘一把的XD
下一個設計模式再見吧~