今天前進到了第四章─ 工廠模式,這章篇幅較長,在實際運用中也非常常見,值得好好理解,不但可以運用在程式設計上,也常常在溝通時聽到這邊用simple factory,這邊用factory來做,這下終於可以完整接收這些意思了~ 就來看看這些工廠系列的模式指的是什麼設計方式吧!
前面 裝飾器模式 有提及我們需要一個有效製作各種裝飾器類別的方法,讓建立裝飾器的過程是有被好好封裝的,這章就馬上要來介紹啦!我們需要一個避免依賴關係、低耦合的結構來進行實例化。
首先,這次的問題是要產生各種pizza,假設我們需要決定pizza種類並進行製作,最直接的寫法如下:
Pizza *orderPizza() ()
{
Pizza *pizza = new Pizza();
pizza->prepare();
pizza->bake();
pizza->cut();
pizza->box();
return pizza;
}
但因為有很多種口味,我們不得不new對應的實例出來,就如同第一章的產生各種鴨子;
因此要加入一些判斷:
Pizza *orderPizza(string type)
{
// Pizza *pizza = new Pizza();
Pizza *pizza = nullptr;
if("cheese" == type)
{
pizza = new CheesePizza();
}
else if("greek" == type)
{
pizza = new GreekPizza();
}
else if("pepperoni" == type)
{
pizza = new PepperoniPizza();
}
else
{
return pizza;
}
pizza->prepare();
pizza->bake();
pizza->cut();
pizza->box();
return pizza;
};
我們不得不new各種pizza的實例,看到這一大堆的if-else,就會覺得它有很高的機率會需要各種修改,例如新增或移除了一些pizza口味。這時回顧天字號第一原則─ 把會變和不會變的部分隔開,我們大概知道要怎麼改了─
SimplePizzaFactory
裡─class SimplePizzaFactory
{
public:
Pizza* createPizza(string type)
{
Pizza *pizza = nullptr;
if("cheese" == type)
{
pizza = new CheesePizza();
}
else if("greek" == type)
{
pizza = new GreekPizza();
}
else if("pepperoni" == type)
{
pizza = new PepperoniPizza();
}
return pizza;
}
};
class PizzaStore
{
SimplePizzaFactory factory;
public:
PizzaStore(SimplePizzaFactory factory)
{
this->factory = factory;
}
Pizza *orderPizza(string type)
{
Pizza *pizza = factory.createPizza(type);
pizza->prepare();
pizza->bake();
pizza->cut();
pizza->box();
return pizza;
};
};
看似只是簡單地把函式一分為二,並分別放到SimplePizzaFactory
與PizzaStore
裡,但背後有其他意義;我們把會變的部分移過去Factory
裡,對PizzaSotre
這個用戶而言就被封裝了,讓用戶端不用再自己做實例化這件事;此外,這個工廠可能也有其他用戶端,這樣就不是一分為二了,且切得乾淨。
而這就是本章介紹的第一個...習慣寫法,還不算是設計模式─簡單工廠 (simple factory)。
這不是真正的設計模式,但很常見,可以從目前的案例看看它的架構:
簡單來說,簡單工廠就是把create
實例化的部分抽出,其他共通的部分保留在原本的地方,並用 "組合" 的方式連接兩者。
接下來我們來考慮更進階的情形─ 如果現在想要有不同的披薩店,可以各自生產專屬口味,但又希望其他共同的部分(prepare, bake等等)不會被改變,該怎麼做呢?
如果依照原本簡單工廠的架構,我們只有一間工廠,就必須在這個factory裡面改動各種程式碼,加入更多的if-else與pizza,不利於比較複雜的生產情形。
明天,我們來看看正式的設計模式─工廠方法。。