簡單工廠、工廠方法與抽象工廠大比拼
簡單工廠、工廠方法和抽象工廠都屬於設計模式建立型,嚴格意義上簡單工廠不屬於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類,可以建立iuser和idepartment的sql和access產品,如果需要更換oracle資料庫呢?又需要在database中修改case分支,新增oracle資料庫的分支判斷,違背開閉原則,不好維護,這時把資料庫作為字串拿出來,反射出場了。
反射+抽象工廠:assembly.load(程式集).createinstance(名稱空間.要例項化類名稱),原來寫死在程式裡,現在字串來是例項化物件(變數可以更換),資料庫使用由db決定,去除database中switch判斷,不過還需要改程式中db的值,不完美,有沒有一種不修改程式的方法,當然可以讀取配置檔案啊。
配置檔案+反射:真正符合開閉原則,讀檔案時給DB字串賦值,寫明用sql還是access,這樣database也不用更改啦。
四、比較:
比較:簡單工廠:生產同一等級任何產品,一個工廠多生產線;對增加新產品無能 為力;
工廠方法:同一等級結構固定產品,多個工廠;
抽象工廠:生產不同系列的全部產品,對增加新產品無能為力。
每種模式都有自己的優點和弊端,只有最適合它的場景,沒有最好的時候,只要滿足自己的需求就是最好的。