所謂工廠,肯定是和生產有關。工廠模式主要包括工廠方法模式和抽象工廠模式,有些人把簡單工廠也作為一種模式,在本文我分別討論簡單工廠模式,工廠方法模式,抽象工廠模式。這些模式中同樣也和生產有關。接下來,我們來看看各種工廠的特點。
簡單工廠模式
上面說了只是有些人把簡單工廠看做是設計模式,其實是一種編程習慣,無論是否是設計模式,本文將先看看其用法,然后簡單給出其類圖,最后說出其特點。
本節將面對多種比薩,先看看當顧客需要一個比薩時的過程:
1.根據類型,制作一個比薩形狀。2.然后進行烘烤3.切4.打包
如果不熟悉的話,完全可以把其想想成面包的做法。
當顧客根據自己的需求要一個比薩時,用代碼模擬這個過程如下:
public class Pizza
{
public void bake() { }
public void cut() { }
public void box() { }
}
public class CheesePizza:Pizza
{
public CheesePizza()
{ }
}
public class GreekPizza : Pizza
{
public GreekPizza(){}
}
public class PepperoniPizza:Pizza
{
public PepperoniPizza() { }
}
public class Store
{
public Pizza OrderPizza(string type)
{
Pizza pizza = null;
if (type=="Cheese")
{
pizza = new CheesePizza();
}
else if (type=="Greek")
{
pizza = new GreekPizza();
}
else if (type == "Pepperoni")
{
pizza = new PepperoniPizza();
}
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
以上的設計方法和我們的以前提到的過的原則(找出經常變化的部分,抽象成類),很明顯在if else 的地方發生經常性變化。
接下來就把if else 放到一個類中。修改后的代碼
public class Store
{
public Pizza OrderPizza(string type)
{
Pizza pizza = null;
//if (type=="Cheese")
//{
// pizza = new CheesePizza();
//}
//else if (type=="Greek")
//{
// pizza = new GreekPizza();
//}
//else if (type == "Pepperoni")
//{
// pizza = new PepperoniPizza();
//}
SimpleFactory factory = new SimpleFactory();
pizza =factory.CreatePizza(type);
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
public class SimpleFactory
{
public Pizza CreatePizza(string type)
{
Pizza pizza = null;
if (type == "Cheese")
{
pizza = new CheesePizza();
}
else if (type == "Greek")
{
pizza = new GreekPizza();
}
else if (type == "Pepperoni")
{
pizza = new PepperoniPizza();
}
return pizza;
}
}
這樣的話,就可以遵循了把變化的部分抽象成一個類。下次需要變化,只需要對變化的類的部分做修改即可。下面給出其UML圖。
簡單工廠的目的,主要負責實現生產對象的細節,根據訂單來生產。每一個商店有對應着自己的工廠。在此,可以將OrderPizza是工廠的一個客戶,當然還可以是其他類似的方法,比如PizzaShopMenu也可以是工廠的客戶。客戶就是為了獲取工廠生成的對象。前者是為了賣給people,后者是為了使用Pizza類獲取其描述和價格等。這樣遵循了找出變化的部分,將其封裝到一個類中的原則,從而到達了復用的目的。
簡單工廠之所以簡單是因為它只根據需要,來生產出來指定的Pizza。特點:所有的產品都由一個工廠來生產。
接下來我們來看看工廠方法的實現。
工廠方法模式
如果是有多個商店,各個商店對於相同名字的pizza都有自己的生成方法。而且,除了生成方法不一樣,其他的烘烤,切,打包,都是使用一樣的步驟。下面就該我們的工廠方法模式出廠了。
由於生產pizza的方法決定於各個商店,不妨假設有兩個商店。其公共的基類,應該有一個抽象的生產方法,具體的生產方法決定於商店。其UML類圖如下:
上面的PizzaStore是一個抽象類,該類具有一個CreatePizza的抽象方法,真正實現的是具體的商店。
除了有多種商店,每個商店有多種Pizza類,而且是Pizza名是相同的,只是地區不一樣,下面Pizza類的命名方式為:地區+Pizza名,其UML類圖為:
商店和pizza的大致聯系如下圖:
在工廠方法中,使用了一個重要的原則:
原則五:依賴倒置:依賴於抽象,不要依賴於具體類
如果沒有使用上述原則,而是直接讓店鋪依賴於每個Pizza類。
如果Pizza的實現變化了,就必須改變PizzaStore。每增加一個Pizza都會增加一個依賴。如果使用工廠方法設計模式的話,其依賴於抽象,不依賴與具體類。我們可以抽象出一個Pizza類,讓所有商店以及所有的Pizza類來依賴它。這里涉及到一個依賴倒置的另一種解釋,高層組件和底層組件都依賴於抽象。而不依賴與具體的實現,高層組件是有底層組件的方法構建 而成的。PizzaStore是由Pizza的Bake,Cut,Box方法構建。那么根據這個原則其大致圖為:
這樣的設計方法,對於任何添加新的Pizza種類,不會影響到PizzaStore。從而實現了松耦合的效果。
工廠方法和簡單工廠設計模式的區別:簡單工廠設計模式,只有一個工廠,每次增加新類,都需要修改SimpleFactory的代碼,不能對工廠的創建方式進行分類管理,全部都由一個工廠制作。工廠方法,可以對工廠進行擴展,也就是可以對Pizza類分類管理,可以由不同的工廠去創建,更加靈活。
這個好比,簡單工廠只有可以看成商店只有一家供應商,需要什么樣子的產品,直接給工廠說,工廠如果沒有的話要不然制造出來對象,要不然告訴供應商,我不能創建。工廠方法可以看成商店有多個供應商,需要的產品,可以有多重選擇。
下面給出工廠方法的測試代碼:
PizzaStore store = new NYPizzaStore();
store.OrderPizza("Greek");
store.OrderPizza("Cheese");
store = new ChicagoPizzaStore();
store.OrderPizza("Greek");
store.OrderPizza("Cheese");
抽象工廠模式
抽象工廠模式的定義:抽象工廠模式提供了一個接口,用於創建相關或依賴對象的家族,而不需要明確指定具體的類。
定義感覺還真有些抽象,下面就把他易於理解化。
抽象工廠允許客戶使用抽象的接口來創建一組相關的產品,而不需要知道實際的具體產品是什么。這樣客戶就從具體的產品中被解耦了。
下面就來看個關於南北方飲食的差異:
主食分別是北方風味和南方風味。無論是南方味道還是北方味道,其都包括主食和調料:北方主要是以面食和辣椒為主,南方主要是以大米和糖為主。
下面就使用抽象工廠來抽象兩個接口,分別是主食和調料,對應還有兩種風味。
接下來是調料和事務的對應實現:
接下來看看其聯系
在上圖中,AbstractFactory接口定義了兩個方法來分別獲得調料和主食。下面的南北風味是可以看出其具體實現。
這樣就可以在前台查看風味的主食和調料就不用關心具體的實現。直接調用其Create方法就行了。
測試代碼:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("南方風味:");
AbstractFactory factory = new SouthFood();
Food food = factory.CreateFood();
Console.WriteLine(food.Name);
Condiment condiment = factory.CreateCondiment();
Console.WriteLine(condiment.Name);
Console.WriteLine("北方風味:");
AbstractFactory factory2 = new NouthFood();
Food food2 = factory2.CreateFood();
Console.WriteLine(food2.Name);
Condiment condiment2 = factory2.CreateCondiment();
Console.WriteLine(condiment2.Name);
Console.ReadKey();
}
}
從該實例,可以看出抽象工廠是定義了多類產品。工廠方法是一個對象有多種做法,所以在抽象工廠中可以使用多個工廠方法。如果理解了工廠方法,那么抽象工廠應該更好理解些。
抽象工廠是單個接口定義了多個方法,所以具體的工廠肯定都要實現創建方法。