1. 程式人生 > >簡單工廠、工廠方法與抽象工廠大比拼

簡單工廠、工廠方法與抽象工廠大比拼

簡單工廠、工廠方法和抽象工廠都屬於設計模式建立型,嚴格意義上簡單工廠不屬於23設計模式之一(違背了開閉原則),本文為了完整描述三工廠演變過程,對三工廠進行了整體的總結和學習,並通過三者之間的特點比較總結出各自的優缺點。

一、簡單工廠:

        在沒有工廠之前,大家都是自給自足,生產一部車或其他工具都是自己來完成,有了工廠之後,告訴它需求就會出來相應的產品,但生產化水平比較低,工廠分工不太明確,社會上只有一個工廠,不論卡車還是公交車都由它來完成,相當於一個工廠多條生產線。

類圖:


程式碼:

/**********************************************************************************
     * 開發人:李立平
     * 開發組:
     * 類說明: 簡單工廠類,用於生產各種汽車
     * 開發時間:2015/8/20 16:05:29
     * 開發版本:V4.0.0    **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace SimpleFactory
{
    class CarFactory
    {
        public static Car CreateCar(string type)
        {
            Car car = null;
            switch (type)
            {
                case "bus":
                    car=new Bus ();
                    break ;
                case "truck":
                    car=new Truck ();
                    break ;
            }
            return car;
        }
    }
}
/**********************************************************************************
     * 開發人:李立平
     * 開發組:
     * 類說明: 車的抽象類,下面有公交車、卡車等,有生產車的虛方法
     * 開發時間:2015/8/20 16:06:03
     * 開發版本:V4.0.0    **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace SimpleFactory
{
   public  class Car
    {
       public virtual void GetCar()
       {
       }
    }
}
/**********************************************************************************
     * 開發人:李立平
     * 開發組:
     * 類說明: 車的具體類之一,公交車
     * 開發時間:2015/8/20 16:06:39
     * 開發版本:V4.0.0    **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace SimpleFactory
{
    public  class Bus:Car
    {
        public override void GetCar()
        {
            Console.WriteLine("生產出公交車!");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SimpleFactory
{
    class Client
    {
        static void Main(string[] args)
        {
            Car car;
            car = CarFactory.CreateCar("bus");//需要生產公交車
            car.GetCar();
        }
    }
}

好處:工廠類包含邏輯判斷,根據客戶端例項化相關類,去除與具體產品依賴,客戶端不管哪個類的例項,把需求給工廠,工廠單獨建立相應例項。是優點也是不足。

不足:如果新增產品,需要修改工廠類,違背開閉原則。工廠方法的出現解決了這一困惑。。。

二、工廠方法:

        隨著專業化程度的提高,工廠分工變得明確,每個工廠生產各自的產品,公交車工廠只管生產公交車,卡車工廠負責生產卡車,這樣如果有新的產品需求,直接增加相應的產品類和對應 工廠類即可。

類圖:


程式碼:和簡單工廠不同的是,多了一個抽象工廠介面,具體工廠類都來實現它。客戶端也來例項化具體工廠類(宣告時候是父類)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AbstractFactory
{
    interface IFactory
    {
        Car CreateCar();
    }
}
/**********************************************************************************
     * 開發人:李立平
     * 開發組:
     * 類說明: 公交車工廠
     * 開發時間:2015/8/20 16:25:07
     * 開發版本:V4.0.0    **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace AbstractFactory
{
    class BusFactory:IFactory 
    {
        public Car CreateCar()
        {
            return new Bus();
        }
    }
}
/**********************************************************************************
     * 開發人:李立平
     * 開發組:
     * 類說明: 客戶端,比如需要一輛公交車
     * 開發時間:2015/8/20 16:06:39
     * 開發版本:V4.0.0    **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AbstractFactory
{
    class Client
    {
        static void Main(string[] args)
        {
            IFactory factory = new BusFactory();//例項化公交車工廠
            Car car = factory.CreateCar();   //公交車工廠創建出公交車
            car.GetCar();
        }
    }
}

好處:遵守開閉原則,直接新增具體產品類和相應工廠類,例項化哪一個工廠放在客戶端

不足:第一:增加一個產品就要增加一個產品工廠類,額外開發,第二:把簡單工廠內部邏輯移到客戶端,所以之前修改工廠類,現在修改客戶端,問題還是存在,抽象工廠的出現了。。。

三、抽象工廠:

      工廠方法雖解決簡單工廠違背開閉原則的問題,但它每個工廠只能生產一種產品,對於系列產品表示無能為力,而且大家都看到工廠能獲益,隨著工廠的增多,使用者的需求,這時有了品牌的概念,比如想要寶馬的卡車,賓士的公交車等。。。

類圖:


程式碼:

/**********************************************************************************
     * 開發人:李立平
     * 開發組:
     * 類說明: 車的抽象類,下面有公交車、卡車等,有生產車的虛方法
     * 開發時間:2015/8/20 16:06:03
     * 開發版本:V4.0.0    **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace AbstractFactory
{
    public class Bus
    {
        public virtual void GetCar()
        {
        }
    }
}
/**********************************************************************************
     * 開發人:李立平
     * 開發組:
     * 類說明: 車的具體類之一,賓士公交車
     * 開發時間:2015/8/20 16:06:39
     * 開發版本:V4.0.0    **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace AbstractFactory
{
    public class BenzBus : Bus
    {
        public override void GetCar()
        {
            Console.WriteLine("生產出賓士公交車!");
        }
    }
}
**********************************************************************************
     * 開發人:李立平
     * 開發組:
     * 類說明: 賓士工廠,生產賓士公交和賓士卡車
     * 開發時間:2015/8/20 16:25:07
     * 開發版本:V4.0.0    **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace AbstractFactory
{
  public  class BenzFactory : IFactory 
    {
        public Bus  CreateBus()  //生產賓士公交
        {
            return new BenzBus();
        }
        public Truck CreateTruck()//生產賓士卡車
        {
            return new BenzTruck();

        }
    }
}
/**********************************************************************************
     * 開發人:李立平
     * 開發組:
     * 類說明: 客戶端,需要賓士公交和寶馬卡車
     * 開發時間:2015/8/20 16:06:39
     * 開發版本:V4.0.0    **********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AbstractFactory
{
    class Client
    {
        static void Main(string[] args)
        {
             Bus bb = new BenzBus();//宣告為父類
            IFactory bf = new BenzFactory();  //建立賓士工廠
            bb = bf.CreateBus(); //生產賓士公交
            bb.GetCar();    

            Truck bt = new BMWTruck();//宣告為父類
            IFactory tf = new BMWFactory();//建立寶馬工廠
            bt = tf.CreateTruck();//生產寶馬卡車
            bt.GetCar();       
        }
    }
}

好處:可以解決工廠方法每個工廠只能生產單一產品的工廠,根據產品需求進一步抽象出一個工廠類的抽象類,所以為抽象工廠。通過改變具體工廠使用不同產品配置,第二:具體建立例項過程與客戶端分離,客戶端通過抽象介面操縱例項,

不足:增加新產品,比如上圖大眾的轎車,就要新增轎車抽象類,和下面的大眾轎車,大眾卡車等,還有修改抽象工廠,和具體的工廠,比如上圖就要新增大眾的具體工廠,要修改的地方太多啦,這時就顯得糟糕了,不過可以通過簡單工廠改進抽象工廠。

抽象工廠的改進(更換資料庫的問題):

    簡單工廠改進抽象工廠:一個database類,可以建立iuseridepartmentsqlaccess產品,如果需要更換oracle資料庫呢?又需要在database中修改case分支,新增oracle資料庫的分支判斷,違背開閉原則,不好維護,這時把資料庫作為字串拿出來,反射出場了。

反射+抽象工廠:assembly.load(程式集).createinstance(名稱空間.要例項化類名稱),原來寫死在程式裡,現在字串來是例項化物件(變數可以更換),資料庫使用由db決定,去除databaseswitch判斷,不過還需要改程式中db的值,不完美,有沒有一種不修改程式的方法,當然可以讀取配置檔案啊。

配置檔案+反射:真正符合開閉原則,讀檔案時給DB字串賦值,寫明用sql還是access,這樣database也不用更改啦。

四、比較:

         比較:簡單工廠:生產同一等級任何產品,一個工廠多生產線;對增加新產品無能 為力;

                       工廠方法:同一等級結構固定產品,多個工廠;

                       抽象工廠:生產不同系列的全部產品,對增加新產品無能為力。

         每種模式都有自己的優點和弊端,只有最適合它的場景,沒有最好的時候,只要滿足自己的需求就是最好的。