.Net簡單工廠模式,工廠模式,抽象工廠模式實例


---恢復內容開始---

1.定義

   簡單工廠模式:是由一個工廠對象決定創建出哪一種產品類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式,可以理解為是不同工廠模式的一個特殊實現。

  工廠模式:定義一個用於創建對象的接口,讓子類決定實例化哪一個類。

  抽象工廠模式:為創建一組相關或相互依賴的對象提供一個接口,而且無需指定他們的具體類。

2.實例

  用工人種蔬菜的例子來說明,蔬菜植物的產品器官有根、莖、葉、花、果等5類,因此按產品器官分類也分成5種,分別是根菜類,莖菜類,葉萊類,花菜類以及果菜類。我們以根菜類,莖菜類為例,分別用簡單工廠模式工廠模式抽象工廠模式來實現。先說明一下:根菜類的

  植物有:大豆,胡蘿卜,大頭菜等;莖菜類的植物有:竹筍,蓮藕,馬鈴薯等。下面便是三種模式下種菜的實現過程。

3.實現過程

  A.簡單工廠模式

    1).在根菜類植物中,工人種植大豆,胡蘿卜,大頭菜,代碼如下: 

 1 namespace 簡單工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 根菜類
 5    /// </summary>
 6     public class RootVegetable
 7     {
 8         public void PlantVegetable()
 9         {
10             Console.WriteLine("親!我在種植大豆,胡蘿卜,還有大頭菜哦!");
11         }
12     }
13 }

    在莖菜類植物中,工人種植竹筍,蓮藕,馬鈴薯,代碼如下: 

 1 namespace 簡單工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 莖菜類
 5     /// </summary>
 6     public class StemVegetable
 7     {
 8         public void PlantVegetable()
 9         {
10             Console.WriteLine("親啊!我在種植竹筍,蓮藕,還有馬鈴薯哦!");
11         }
12     }
13 }

    2)進一步抽象,為它們抽象出共同的父類,蔬菜接口,如圖:

    

      

      

      抽象后的代碼如下:    

 1 namespace 簡單工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 蔬菜接口
 5     /// </summary>
 6     public abstract class Vegetable
 7     {
 8         public abstract void PlantVegetable();
 9     }
10 }
 1 namespace 簡單工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 根菜類
 5     /// </summary>
 6     public class RootVegetable:Vegetable
 7     {
 8         public override void PlantVegetable()
 9         {
10             Console.WriteLine("親!我在種植大豆,胡蘿卜,還有大頭菜哦!");
11         }
12     }
13 }
 1 namespace 簡單工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 莖菜類
 5     /// </summary>
 6     public class StemVegetable:Vegetable
 7     {
 8         public override void PlantVegetable()
 9         {
10             Console.WriteLine("親啊!我在種植竹筍,蓮藕,還有馬鈴薯哦!");
11         }
12     }
13 }

    3).此時如果工人再種植葉萊類植物的話,只需要增加一個繼承父類Vegetable的子類來實現,這樣的設計滿足了類之間的層次關系,每一個類都只負責一件具體的事情。在應用程序中,當工人種植根菜類植物時,代碼如下:

namespace 簡單工廠模式_RootVegetableAndStemVegetable
{
    public class Program
    {
        public static void Main(string[] args)
        {
            ///獲得莖菜類蔬菜
            Vegetable vge = new RootVegetable();
            vge.PlantVegetable();
            Console.ReadLine();
        }
    }
}

    如果工人由種植根菜類植物變成種植莖菜類植物或者葉菜類植物,那么在應用程序中,諸多代碼就要改變,工作量就會增加,此時就需要解耦具體的種植哪類植物和應用程序。這就要引入簡單工廠模式了,代碼如下:

 1 namespace 簡單工廠模式_RootVegetableAndStemVegetable
 2 {
 3     public class VegetableFactory
 4     {
 5         public static Vegetable GetVegetableInstance(string vegetable)
 6         {
 7             Vegetable vge = null;
 8             if (vegetable.Equals("根菜類蔬菜"))
 9             {
10                 return new RootVegetable();
11             }
12             else if (vegetable.Equals("莖菜類蔬菜"))
13             {
14                 return new StemVegetable();
15             }
16 
17             return vge;
18         }
19     }
20 }

    此時應用程序代碼如下:

 1 namespace 簡單工廠模式_RootVegetableAndStemVegetable
 2 {
 3     public class Program
 4     {
 5         public static void Main(string[] args)
 6         {
 7             ///獲得莖菜類蔬菜
 8             Vegetable vge1 = (Vegetable)VegetableFactory.GetVegetableInstance("莖菜類蔬菜");
 9             vge1.PlantVegetable();
10             ///獲得根菜類蔬菜
11             Vegetable vge2 = (Vegetable)VegetableFactory.GetVegetableInstance("根菜類蔬菜");
12             vge2.PlantVegetable();
13             Console.ReadLine();
14         }
15     }
16 }

    VegetableFactory解決了客戶端直接依賴於具體對象的問題,客戶端可以消除直接創建對象的責任,工人只需根據蔬菜的類型,便可進行種植對應的蔬菜。總之,簡單工廠模式實現了對責任的分割。

    4).該簡單工廠模式UML圖:

    

    5).缺點:工廠類集中了所有產品創建邏輯,一旦添加新產品就不得不修改工廠邏輯,這樣就會造成工廠邏輯過於復雜,並且,它所能創建的類只能是事先考慮到的。對系統的維護和擴展相當不利。

      下面就需要工廠模式來解決了。

  B.工廠模式

    1).由於簡單工廠模式系統難以擴展,一旦添加新的蔬菜類型就不得不修改VegetableFactory中的方法,這樣就會造成簡單工廠的實現邏輯過於復雜,然而工廠模式可以解決簡單工廠模式中存在的這個問題。

      在 A.簡單工廠模式 3) 小點中(前面的都相同),如果工人由種植根菜類植物變成種植莖菜類植物或者葉菜類植物,那么在應用程序中,諸多代碼就要改變,工作量就會增加,此時就需要解耦具體的種植哪類植物和應用程序。

      如果此時引入工廠模式,由於每一種類型的蔬菜就是工廠種植的產品,有兩種類型的蔬菜,就需要兩個工廠去種植,代碼如下:

 1 namespace 工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 根菜類
 5     /// </summary>
 6     public class RootVegetableFactory
 7     {
 8         public Vegetable GetVegetableInstance()
 9         {
10             return new RootVegetable();
11         }
12     }
13 }

 

 1 namespace 工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 莖菜類
 5     /// </summary>
       public Vegetable GetVegetableInstance()
    {
        return new StemVegetable();
    }
13 }

 

    2).這兩個工廠是平級的,在此基礎上抽象出一個公共的接口,如圖:

      代碼如下:

1 namespace 工廠模式_RootVegetableAndStemVegetable
2 {
3     public abstract class VegetableFactory
4     {
5         public abstract Vegetable GetVegetableInstance();
6     }
7 }
 1 namespace 工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 根菜類
 5     /// </summary>
 6     public class RootVegetableFactory:VegetableFactory
 7     {
 8         public override Vegetable GetVegetableInstance()
 9         {
10             return new RootVegetable();
11         }
12     }
13 }
namespace 工廠模式_RootVegetableAndStemVegetable
{
    /// <summary>
    /// 莖菜類
    /// </summary>
    public class StemVegetableFactory:VegetableFactory
    {
        public override Vegetable GetVegetableInstance()
        {
            return new StemVegetable();
        }
    }
}

    

    3).工廠模式之所以可以解決簡單工廠的模式,是因為它的實現把具體產品的創建推遲到子類中,此時工廠類不再負責所有產品的創建,而只是給出具體工廠必須實現的接口,這樣工廠方法模式就可以允許系統不修改工廠類邏輯的情況下來添加新產品。

        如果此時在種植葉菜類蔬菜,只需增加葉菜類蔬菜工廠和葉菜類蔬菜類。而不用像簡單工廠模式中那樣去修改工廠類中的實現。應用程序代碼如下:

 

 1 namespace 工廠模式_RootVegetableAndStemVegetable
 2 {
 3     public class Program
 4     {
 5         public static void Main(string[] args)
 6         {
 7             // 初始化工廠
 8             VegetableFactory Factory = new RootVegetableFactory();
 9             //種植根菜類蔬菜
10             Vegetable vge = Factory.GetVegetableInstance();
11             vge.PlantVegetable();
12             Console.ReadLine();
13         }
14     }
15 }

    此時如果想種植莖菜類蔬菜,只需更改

VegetableFactory Factory = new StemVegetableFactory();

    其余地方不需修改。如果利用.NET中的反射機制來進一步修改我們的程序,這時就要用到配置文件了,這樣可以避免上述的修改。配置文件如下:

1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3     <startup> 
4         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
5     </startup>
6   <appSettings>
7     <add key="factoryName" value="工廠模式_RootVegetableAndStemVegetable.RootVegetableFactory"/>
8   </appSettings>
9 </configuration>

    應用程序如下:

namespace 工廠模式_RootVegetableAndStemVegetable
{
    public class Program
    {
        public static void Main(string[] args)
        {
            string factoryName = ConfigurationManager.AppSettings["factoryName"];
            VegetableFactory vf =(VegetableFactory) Assembly.Load("工廠模式_RootVegetableAndStemVegetable").CreateInstance(factoryName);
            Vegetable vge = vf.GetVegetableInstance();
            vge.PlantVegetable();
            Console.ReadLine();
        }
    }
}

    注意:1.Assembly.Load("XXX")的使用說明如下:XXX並不是命名空間,而是程序集名稱,也就是dll的名稱,,可以在bin目錄下看一下,而不是類名!

        即:Assembly.Load("程序集").CreateInstance("命名空間.類")

      2.注意CreateInstance()一定是 命名空間.類名,否則創建的實例為空.

    4)該工廠模式UML圖

    5)缺點:在工廠模式中,一個工廠只能創建一種產品,如果要求工廠創建多種產品,工廠模式就不好用了。下面就需要 抽象工廠模式 來解決了。

  C.抽象工廠模式

    1).隨着科技的發展,工人逐步要種植轉基因與非轉基因食品了,在以前的蔬菜種類上又增加了一個層次,這個時候無法將其作為一個層次來解決,所以必須采用抽象工廠的方式來解決。依然以種植根菜類蔬菜和莖菜類蔬菜為例。

      此時在蔬菜下有根菜類蔬菜類型莖菜類蔬菜類型,在根菜類蔬菜類型下 有轉基因根菜類蔬菜非轉基因食品根菜類蔬菜,在莖菜類蔬菜類型下有 轉基因莖菜類蔬菜 和 非轉基因莖菜類蔬菜 。如圖:

 

      代碼如下:

 

namespace  抽象工廠模式_RootVegetableAndStemVegetable{
    /// <summary>
    /// 蔬菜接口
    /// </summary>
    interface Vegetable
    {
    }
}
 1 namespace  抽象工廠模式_RootVegetableAndStemVegetable
2 { 3 /// <summary> 4 /// 根菜 5 /// </summary> 6 public abstract class RootVegetable:Vegetable 7 { 8 public abstract void PlantRootVegetable(); 9 } 10 }
 1 namespace  抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 莖菜
 5     /// </summary>
 6     public abstract class StemVegetable:Vegetable
 7     {
 8         public abstract void PlantStemVegetable();
 9     }
10 }
 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 轉基因根菜
 5     /// </summary>
 6     public class GMFRootVegetable:RootVegetable
 7     {
 8         public override void PlantRootVegetable()
 9         {
10             Console.WriteLine("親!我在種植轉基因類型的大豆,胡蘿卜,還有大頭菜哦!");
11         }
12     }
13 }
 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 非轉基因根菜
 5     /// </summary>
 6     public class NonGMFRootVegetable:RootVegetable
 7     {
 8         public override void PlantRootVegetable()
 9         {
10             Console.WriteLine("親!我在種植非轉基因類型的大豆,胡蘿卜,還有大頭菜哦!");
11         }
12     }
13 }
 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 轉基因莖菜
 5     /// </summary>
 6     public class GMFStemVegetable:StemVegetable
 7     {
 8         public override void PlantStemVegetable()
 9         {
10             Console.WriteLine("親啊!我在種植轉基因類型的芹菜,蓮藕,還有馬鈴薯哦!");
11         }
12     }
13 }
 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 非轉基因莖菜
 5     /// </summary>
 6     public class NonGMFStemVegetable:StemVegetable
 7     {
 8         public override void PlantStemVegetable()
 9         {
10             Console.WriteLine("親啊!我在種植非轉基因類型的芹菜,蓮藕,還有馬鈴薯哦!");
11         }
12     }
13 }

 

    2).由於現在種植轉基因與非轉基因蔬菜,可以創建 轉基因蔬菜工廠 非轉基因蔬菜工廠,在 轉基因蔬菜工廠 下可以種植 轉基因根菜類蔬菜轉基因莖菜類蔬菜,非轉基因蔬菜工廠 下可以種植 轉基因根菜類蔬菜 和 非轉基因莖菜類蔬菜

        如果現在工人只要求是種植轉基因蔬菜,代碼如下:

 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 轉基因工廠
 5     /// </summary>
 6     public class VegetableFactory    {
 7         /// <summary>
 8         /// 轉基因根菜
 9         /// </summary>
10         /// <returns></returns>
11         public  RootVegetable GetRootVegetableInstance()
12         {
13             return new GMFRootVegetable();
14         }
15         /// <summary>
16         /// 轉基因莖菜
17         /// </summary>
18         /// <returns></returns>
19         public StemVegetable GetStemVegetableInstance()
20         {
21             return new GMFStemVegetable();
22         }
23     }
24 }

      可以很好地解決種植轉基因蔬菜的問題,但一段時間后,工人又要種植非轉基因蔬菜蔬菜,此時就要修改系統源代碼,修改VegetableFactory這個類,代碼如下:

 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 非轉基因工廠
 5     /// </summary>
 6     public class VegetableFactory:
 7     {
 8         /// <summary>
 9         /// 非轉基因根菜
10         /// </summary>
11         /// <returns></returns>
12         public  RootVegetable GetRootVegetableInstance()
13         {
14             return new NonGMFRootVegetable();
15         }
16         /// <summary>
17         /// 非轉基因莖菜
18         /// </summary>
19         /// <returns></returns>
20         public StemVegetable GetStemVegetableInstance()
21         {
22             return new NonGMFStemVegetable();
23         }
24     }
25 }

      最終的工作都是對VegetableFactory這個類進行修改。工作量依然沒有減少。此時引入 抽象工廠模式,並在 抽象工廠模式 加一個靜態方法,便可解決這個問題。如圖:

      代碼如下:

 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 抽象工廠
 5     /// </summary>
 6     public abstract class AbstractFactory
 7     {
 8         /// <summary>
 9         /// 獲得根菜類蔬菜
10         /// </summary>
11         public abstract RootVegetable GetRootVegetableInstance();
12         /// <summary>
13         /// 獲得莖菜類蔬菜
14         /// </summary>
15         public abstract StemVegetable GetStemVegetableInstance();
16         /// <summary>
17         /// 獲得轉基因工廠還是非轉基因工廠
18         /// </summary>
19         public static AbstractFactory GetAbstractFactoryInstance(string factoryName)
20         {
21             AbstractFactory instance = null;
22             if (factoryName.Equals("轉基因工廠"))
23             {
24                 instance= new GMFVegetableFactory();
25             }
26             else if (factoryName.Equals("非轉基因工廠"))
27             {
28                 instance = new NonGMFVegetableFactory();
29             }
30 
31             return instance;
32         }
33     }
34 }
 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 轉基因工廠
 5     /// </summary>
 6     public class GMFVegetableFactory:AbstractFactory
 7     {
 8         /// <summary>
 9         /// 轉基因根菜
10         /// </summary>
11         /// <returns></returns>
12         public override RootVegetable GetRootVegetableInstance()
13         {
14             return new GMFRootVegetable();
15         }
16         /// <summary>
17         /// 轉基因莖菜
18         /// </summary>
19         /// <returns></returns>
20         public override StemVegetable GetStemVegetableInstance()
21         {
22             return new GMFStemVegetable();
23         }
24     }
25 }
 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 非轉基因工廠
 5     /// </summary>
 6     public class NonGMFVegetableFactory:AbstractFactory
 7     {
 8         /// <summary>
 9         /// 非轉基因根菜
10         /// </summary>
11         /// <returns></returns>
12         public override RootVegetable GetRootVegetableInstance()
13         {
14             return new NonGMFRootVegetable();
15         }
16         /// <summary>
17         /// 非轉基因莖菜
18         /// </summary>
19         /// <returns></returns>
20         public override StemVegetable GetStemVegetableInstance()
21         {
22             return new NonGMFStemVegetable();
23         }
24     }
25 }

    應用程序代碼:

 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     public class Program
 4     {
 5         public static void Main(string[] args)
 6         {
 7             AbstractFactory af = AbstractFactory.GetAbstractFactoryInstance("轉基因工廠");
 8             ///種植轉基因類型蔬菜
 9             RootVegetable rootVge = af.GetRootVegetableInstance();
10             rootVge.PlantRootVegetable();
11             Console.ReadLine();
12         }
13     }
14 }

    如果想種植 非轉基因根菜類蔬菜,只需修改:

1 AbstractFactory af = AbstractFactory.GetAbstractFactoryInstance("非轉基因工廠");

    不用再擔心到底是種植轉基因還是非轉基因蔬菜,修改的地方非常少。

 

    3).但也有一個小問題,如果有一天,科技已經發展到一定程度,種植需要很長時間,工人直接·采用3D打印技術,打印各種類型的蔬菜,這是在原有的層次上又增加了一個層次,增加一個

    3D打印蔬菜工廠到不是難事,但要修改AbstractFactory這個類,在GetAbstractFactoryInstance(string factoryName)方法中添加一個if(){}判斷語句,依然要修改源代碼。可以利用

    .NET中的反射機制來進一步修改我們的程序,這時就要用到配置文件了,這樣可以避免上述的修改。配置文件如下:

1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3     <startup> 
4         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
5     </startup>
6   <appSettings>
7     <add key="factoryName" value="抽象工廠模式_RootVegetableAndStemVegetable.GMFVegetableFactory"/>
8   </appSettings>
9 </configuration>

  此時AbstractFactory類修改如下:

 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     /// <summary>
 4     /// 抽象工廠
 5     /// </summary>
 6     public abstract class AbstractFactory
 7     {
 8         /// <summary>
 9         /// 獲得根菜類蔬菜
10         /// </summary>
11         public abstract RootVegetable GetRootVegetableInstance();
12         /// <summary>
13         /// 獲得莖菜類蔬菜
14         /// </summary>
15         public abstract StemVegetable GetStemVegetableInstance();
16         /// <summary>
17         /// 獲得轉基因工廠還是非轉基因工廠
18         /// </summary>
19         public static AbstractFactory GetAbstractFactoryInstance()
20         {
21             string factoryName = ConfigurationSettings.AppSettings["factoryName"];
22             AbstractFactory instance = null;
23             if (!factoryName.Equals(string.Empty))
24             {
25                 instance = (AbstractFactory)Assembly.Load("抽象工廠模式_RootVegetableAndStemVegetable").CreateInstance(factoryName);
26             }
27             return instance;
28         }
29     }
30 }

    應用程序如下:

 1 namespace 抽象工廠模式_RootVegetableAndStemVegetable
 2 {
 3     public class Program
 4     {
 5         public static void Main(string[] args)
 6         {
 7             AbstractFactory af = AbstractFactory.GetAbstractFactoryInstance();
 8             ///種植轉基因類型蔬菜
 9             RootVegetable rootVge = af.GetRootVegetableInstance();
10             rootVge.PlantRootVegetable();
11             Console.ReadLine();
12         }
13     }
14 }

    當再增加一個層次時,就不必修改AbstractFactory這個類,只需修改配置文件即可。

  4).缺點: 難以支持新種類的產品。難以擴展抽象工廠以生產新種類的產品。這是因為抽象工廠接口確定了可以被創建的產品集合,支持新種類的產品就需要擴展該工廠接口,這將涉及抽象工廠類及其所有子類的改變,這樣也就違背了“開發——封閉”原則。

    5).該抽象工廠模式的UML圖


4.工廠模式VS抽象工廠模式(轉載)

  1.區別在於產品,如果產品單一,最合適用工廠模式,但是如果有多個業務品種、業務分類時,通過抽象工廠模式產生需要的對象是一種非常好的解決方式。

   再通俗深化理解下:工廠模式針對的是一個產品等級結構 ,抽象工廠模式針對的是面向多個產品等級結構的。

  2.工廠方法模式與抽象工廠模式對比:

                                            工廠方法模式                                                                                     抽象工廠模式
 
                                              針對的是一個產品等級結構                                                              針對的是面向多個產品等級結構
                                               一個抽象產品類                                                                            多個抽象產品類
                                              可以派生出多個具體產品類                                                               每個抽象產品類可以派生出多個具體產品類
                                              一個抽象工廠類,可以派生出多個具體工廠類                                        一個抽象工廠類,可以派生出多個具體工廠類
                                              每個具體工廠類只能創建一個具體產品類的實例                                     每個具體工廠類可以創建多個具體產品類的實例 

 

5.總結

  這是本人第一次寫博客,對簡單工廠模式,工廠模式以及抽象工廠模式進行了一個小結,肯定存在許多的不足,希望各位能夠指出,在此謝過!

 

參考文獻:

http://www.cnblogs.com/zhili/p/3317623.html

http://www.cnblogs.com/Terrylee/archive/2006/01/04/310716.html

http://blog.csdn.net/wyxhd2008/article/details/5597975


 

 

 

 

 

 

 

 

 

 

 

   

 

 

 

 

---恢復內容結束---


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM