設計模式(一)——簡單工廠和工廠方法的異同
一、簡單工廠
1.定義:
簡單工廠模式(Simple Factory Pattern):又稱為靜態工廠方法(Static Factory Method)模式。它屬於類建立型模式,在簡單工廠模式中,可以根據引數的不同返回不同型別的例項。簡單工廠模式專門定義一個類來負責建立其他的例項,別建立的例項通常都具有共同的父類。
(客戶不知道具體步驟,只要滿足自己的需求就行。)
2.模式結構
簡單工廠模式包含如下角色
Factory:工廠角色
Product:抽象產品角色
ConcreteProduct:具體產品角色
3.優缺點
(1)優點:
A.工廠類含有必要的判斷邏輯,可以決定在什麼時候建立哪一個產品類的例項,客戶端可以免除直接建立產品物件的責任,而僅僅“消費”產品;簡單工廠通過這種做法實現了對責任的分割,它提供了專門的工廠類用於建立物件。
B.客戶端無須知道建立的具體產品類的類名,之需要知道具體產品類對應的引數即可,對於一些複雜的類名,通過簡單工廠模式可以減少使用者的記憶量。
C.通過引入配置檔案,可以在不修改任何客戶端程式碼的情況下更換課增加新的具體產品類。在一定程度上提高了系統的靈活性。
(2)缺點
由於工廠類中集中了所有的產品建立邏輯,一旦不能正常工作,整個系統都要受到影響。
使用簡單工廠模式將會增加系統中類的個數,在一定程度上增加了系統的複雜度和理解難度。
系統擴充套件困難,一旦新增新產品就不得不修改工廠邏輯,在產品型別較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴充套件和維護。
簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構。
4.適用環境
(1)工廠類負責建立的物件較少:由於建立物件較少,不會造成工廠方法中的業務邏輯過於複雜。
(2)客戶端只知道傳入工廠的引數,對於如何建立物件不關心:客戶端不需要關心建立細節,甚至連類名都不需要記住,只需要知道型別所對應的引數。
定義一個食物抽象類
public abstract class Food
{
// 輸出點了什麼菜
public abstract void Print();
}
/// <summary>
/// 西紅柿炒雞蛋這道菜
/// </summary>
public class TomatoScrambledEggs : Food
{
public override void Print()
{
Console.WriteLine("一份西紅柿炒蛋!");
}
}
/// <summary>
/// 土豆肉絲這道菜
/// </summary>
public class ShreddedPorkWithPotatoes : Food
{
public override void Print()
{
Console.WriteLine("一份土豆肉絲");
}
//宣告一個顧客類
// <summary>
/// 自己做飯的情況
/// 沒有簡單工廠之前,客戶想吃什麼菜只能自己炒的
/// </summary>
public class Customer
{
/// <summary>
/// 燒菜方法
/// </summary>
// <param name="type"></param>
/// <returns></returns>
public static Food Cook(string type)
{
Food food = null;
// 客戶A說:我想吃西紅柿炒蛋怎麼辦?
// 客戶B說:那你就自己燒啊
// 客戶A說: 好吧,那就自己做吧
if (type.Equals("西紅柿炒蛋"))
{
food = new TomatoScrambledEggs();
}
// 我又想吃土豆肉絲, 這個還是得自己做
// 我覺得自己做好累哦,如果能有人幫我做就好了?
else if (type.Equals("土豆肉絲"))
{
food = new ShreddedPorkWithPotatoes();
}
return food;
}
//客戶端
class Program
{
static void Main(string[] args)
{
// 做西紅柿炒蛋
Food food1 = Cook("西紅柿炒蛋");
food1.Print();
Food food2 = Cook("土豆肉絲");
food2.Print();
Console.Read();
}
二、工廠模式
1.定義:
工廠方法模式(Factory Method Pattern)又稱為工廠模式,也叫虛擬構造器(Polymorphic Factory)模式,它屬於類建立性模式。在工廠方法模式中,工廠父類負責定義建立產品物件的公共介面,而工廠子類則負責生成具體的產品物件,這樣做的目的時將產品類的例項化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該例項化哪一個具體產品類。
2.模式結構
Product:抽象產品
ConcreteProduct:具體產品
Factory:抽象工廠
ConcrateFactory:具體工廠
3.優缺點
(1)優點
在工廠方法模式中,工廠方法用來建立客戶所需要的產品,同時還向客戶隱藏了哪種具體產品類將被例項化這一細節,使用者只需要關心所需產品對應的工廠,無須關心建立細節,甚至無須知道具體產品類的類名。
基於工廠角色和產品角色的多型性設計是工廠方法模式的關鍵。它能夠使工廠可以自主確定建立何種產品物件,而如何建立這個物件的細節則完全封裝在具體工廠內部。工廠方法模式之所以又被稱為多型工廠模式,是因為所有的具體工廠類都具有同一抽象父類。
使用工廠方法模式的另一個優點是在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的介面,無須修改客戶端,也無須修改其他的具體工廠和具體產品,而只要新增一個具體工廠和具體產品就可以了。這樣,系統的可擴充套件性也就變得非常好,完全符合“開閉原則”。
(2)缺點
在新增新產品時,需要編寫新的具體產品類,而且還要提供與之對應的具體工廠類,系統中類的個數將成對增加,在一定程度上增加了系統的複雜度,有更多的類需要編譯和執行,會給系統帶來一些額外的開銷。
由於考慮到系統的可擴充套件性,需要引入抽象層,在客戶端程式碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度,且在實現時可能需要用到DOM、反射等技術,增加了系統的實現難度。
(3) 模式擴充套件
使用多個工廠方法:在抽象工廠角色中可以定義多個工廠方法,從而使具
體工廠角色實現這些不同的工廠方法,這些方法可以包含不同的業務邏輯,以滿足對不同的產品物件的需求。
產品物件的重複使用:工廠物件將已經建立過的產品儲存到一個集合(如
陣列、List等) 中,然後根據客戶對產品的請求,對集合進行查詢。如果有滿足要求的產品物件,就直接將該產品返回客戶端;如果集合中沒有這樣的產品物件,那麼就建立一一個新的滿足要求的產品物件,然後將這個物件在增加到集合中,再返回給客戶端。
多型性的喪失和模式的退化:如果工廠僅僅返回一個具體產品物件,便違
背了工廠方法的用意,發生退化,此時就不再是工廠方法模式了。一般來說,工廠物件應當有一個抽象的父型別,如果工廠等級結構中只有一一個具體工廠類的話,抽象工廠就可以省略,也將發生了退化。當只有一個具體工廠,在具體工廠中可以建立所有的產品物件,並且工廠方法設計為靜態方法時,工廠方法模式就退化成簡單工廠模式
雷鋒工廠例項
//工廠方法模式,工廠介面
public interface Factory {
LeiFeng createLeiFengFactory();
}
//雷鋒
public interface LeiFeng {
void sweep();//掃地
void wash();//洗衣
void buyrice();//做飯
}
//使用簡單工廠
public class SimpleFactory {
public static LeiFeng createLeiFeng(String type){
if("大學生".equals(type)){
return new Student();
}else if("志願者".equals(type)){
return new Valuator();
}
return null;
}
}
//學做雷鋒的大學生
public class Student implements LeiFeng{
public void buyrice() {
System.out.println("大學生做飯");
}
public void sweep() {
// TODO Auto-generated method stub
System.out.println("大學生掃地");
}
public void wash() {
// TODO Auto-generated method stub
System.out.println("大學生洗衣");
}
}
//學做雷鋒的志願者
public class Valuator implements LeiFeng{
public void buyrice() {
System.out.println("志願者做飯");
}
public void sweep() {
// TODO Auto-generated method stub
System.out.println("志願者掃地");
}
public void wash() {
// TODO Auto-generated method stub
System.out.println("志願者洗衣");
}
}
//學生工廠
public class StudentFactory implements Factory{
public LeiFeng createLeiFengFactory() {
return new Student();
}
}
//志願者工廠
public class ValuatorFactory implements Factory{
public LeiFeng createLeiFengFactory() {
return new Valuator();
}
}
public static void main(String[] args) {
//第一種方式:傳統方式,直接new
//這個時候如果要把大學生給改成志願者的話需要把三個類都給替換掉
//如果大學生多的話那替換就會變得很麻煩,而且程式碼不美觀
LeiFeng f1=new Student();
f1.wash();
LeiFeng f2=new Student();
f2.sweep();
LeiFeng f3=new Student();
f3.buyrice();
//第二種方式,簡單工廠模式
//這個時候你就會發現,這裡有兩句重複的程式碼,如果要改成
//志願者,也要修改兩次,如果數量多的話那修改也多
LeiFeng f11=SimpleFactory.createLeiFeng("大學生");
f11.buyrice();
LeiFeng f22=SimpleFactory.createLeiFeng("大學生");
f22.wash();
//第三種方式,使用工廠方法模式
Factory fac=new StudentFactory();//像這裡的話只需要替換這個工廠類名即可
LeiFeng f4=fac.createLeiFengFactory();
f4.buyrice();
LeiFeng f5=fac.createLeiFengFactory();
f5.wash();
}
}