1.什么是簡單工廠
現實中的工廠負責生產產品,顧名思義,編程中的簡單工廠就是一個生產對象的類,它的主要作用是創建具體的產品類實例。我們以一個生產鼠標為例來分析簡單工廠的作用,鼠標有兩種:戴爾鼠標和惠普鼠標,代碼如下:
//鼠標抽象類 public abstract class Mouse { public abstract void Print(); } //戴爾鼠標 public class DellMouse : Mouse { public override void Print() { Console.WriteLine("生產了一個Dell鼠標!"); } } //惠普鼠標 public class HpMouse : Mouse { public override void Print() { Console.WriteLine("生產了一個惠普鼠標!"); } }
客戶端代碼:
class Program { static void Main(string[] args) { Mouse mouse1 = new DellMouse(); Mouse mouse2 = new DellMouse(); Mouse mouse3 = new DellMouse(); Mouse mouse4 = new DellMouse(); Mouse mouse5 = new DellMouse(); mouse1.Print(); } }
程序運行如下:
我們可以看到程序運行沒有問題,通過new一個DellMouse我們可以創建一個戴爾的鼠標,這時有一個問題,如果我們不想要戴爾鼠標了,要全部生產惠普鼠標怎么辦呢?最簡單直接的方法就是把 new DellMouse全部替換成 new HpMouse 。如果我們的軟件中new了100個DellMouse實例呢?一個一個地去替換會是一個巨大的工作量,同時通過new的方式來創建戴爾鼠標的實例,會讓DellMouse類和客戶端產生強耦合關系,這時候使用簡單工廠就可以幫助我們降低耦合,減少工作量了。添加一個MouseFactory簡單工廠類,這個工廠類專門來創建Mouse的實例:
/// <summary> /// 鼠標工廠類 /// </summary> public class MouseFactory { private Mouse mouse = null; public Mouse CreateMouse(string brand) { switch (brand) { case "dell": mouse = new DellMouse(); break; case "hp": mouse = new HpMouse(); break; default: break; } return mouse; } }
客戶端的代碼就可以改成:
class Program { static void Main(string[] args) { //實例化一個工廠類 MouseFactory mouseFactory = new MouseFactory(); //通過工廠類創建鼠標 Mouse mouse1 = mouseFactory.CreateMouse("dell"); Mouse mouse2 = mouseFactory.CreateMouse("dell"); Mouse mouse3 = mouseFactory.CreateMouse("dell"); Mouse mouse4 = mouseFactory.CreateMouse("dell"); Mouse mouse5 = mouseFactory.CreateMouse("dell"); mouse1.Print(); Console.ReadKey(); } }
運行程序結果一樣的,這樣做有什么好處呢?我們看到我們把以前的 new DellMouse() 替換成了 mouseFactory.Create("dell") ,客戶端和DellMouse的耦合變成了 客戶端<-->MouseFactory<-->DellMouse形式,有效降低了客戶端和DellMouse間的耦合。我們還用一個疑問,程序改成這樣的話,如果我們想把戴爾鼠標全部換成惠普鼠標,要把工廠類的參數"dell"換成"hp",不是還要改100次?任務量沒有降低呀!對於這個問題,我們可以把品牌名brand存放在一個地方,如配置文件中,這樣我們想切換鼠標品牌時就不用修改代碼,直接修改配置文件即可,如下:
配置文件:
<appSettings> <add key="dbname" value="dell"/> </appSettings>
工廠類修改為:
/// <summary> /// 鼠標工廠類 /// </summary> public class MouseFactory { //從配置文件中讀取品牌 private static readonly string brand = ConfigurationManager.AppSettings["brand"]; private Mouse mouse = null; public Mouse CreateMouse() { switch (brand) { case "dell": mouse = new DellMouse(); break; case "hp": mouse = new HpMouse(); break; default: break; } return mouse; } }
客戶端代碼就不用傳參數了,如下:
class Program { static void Main(string[] args) { //實例化一個工廠類 MouseFactory mouseFactory = new MouseFactory(); //通過工廠類創建鼠標 Mouse mouse1 = mouseFactory.CreateMouse(); Mouse mouse2 = mouseFactory.CreateMouse(); Mouse mouse3 = mouseFactory.CreateMouse(); Mouse mouse4 = mouseFactory.CreateMouse(); Mouse mouse5 = mouseFactory.CreateMouse(); mouse1.Print(); Console.ReadKey(); } }
現在我們想把生產的鼠標都換成惠普鼠標,只需要將配置文件中的dell改成hp即可,修改配置文件后運行結果如下:
大功告成!這時有一個問題,如果我們想生產華碩鼠標怎么辦呢?除了添加一個繼承Mouse的AsusMouse類外,還要在MouseFactory中添加一段case 代碼。按照開閉原則,添加一個實現類沒什么問題,開閉原則中對添加開放;但是修改MouseFactory工廠類就違背了對修改閉合的原則了。后邊的工廠模式就是專門用來解決這個問題的。
2.小結
上邊例子的類圖:
簡單工廠的優點:
1.簡單工廠可以有效地降低客戶端和具體對象的耦合,將new具體對象的任務交給了一個簡單工廠類
2可以有效的進行代碼復用,如客戶端A和客戶端B都需要一個具體對象,客戶端A和客戶端B可以通過同一個簡單工廠來獲取具體類型的實例
簡單工廠的缺點:
一定程度上違背了開閉原則,在新增產品時需要修改簡單工廠類