設(shè)計(jì)模式
設(shè)計(jì)模式--------設(shè)計(jì)原則
前言
兩個(gè)月前寫過一次設(shè)計(jì)模式系列,但很不滿意就刪除了。顯然希望能做到學(xué)以致用,而非看書總結(jié),設(shè)計(jì)模式絕對(duì)是你解決問題的一個(gè)思路,但在這有點(diǎn)自己的小建議,設(shè)計(jì)模式
并不是用作提高你代碼的效率,用它的目的只是讓你的代碼看起來更規(guī)范,更易擴(kuò)展與維護(hù)。所以有的時(shí)候你站在你自身需要去選擇要不要使用設(shè)計(jì)模式。上周工作當(dāng)中有一個(gè)需求
正好是適合用工廠模式來解決的,所以就在這給大家討論討論工廠模式吧。
1.簡(jiǎn)單工廠模式
在工廠模式中,我們?cè)趧?chuàng)建對(duì)象時(shí)不會(huì)對(duì)客戶端暴露創(chuàng)建邏輯,并且是通過使用一個(gè)共同的接口來指向新創(chuàng)建的對(duì)象。
比如說,我要給其他終端提供保存實(shí)例的接口,但是實(shí)例卻用很多個(gè),這時(shí)提供的接口,如果每個(gè)實(shí)例都提供一邊,就會(huì)變成這樣提供多個(gè)端口,如果要增加就要繼續(xù)提供接口,故
此我就想到了用工廠模式。
1.1.簡(jiǎn)介:
就好比中午你下樓去吃飯,別人問你干啥去?你說我去吃黃燜雞,我去吃燴面,我去吃肯德基,去吃麻辣燙。。。。這些好像沒錯(cuò),但是估計(jì)你不會(huì)這么回答,你一般都是回答
我去吃飯。這就是工廠模式要走的,具體你要吃什么東西,不用告訴別人,別人問的主題是你去干什么,你告訴他你娶吃飯就行,具體你要吃什么,是你自己的決定,無需說出來。
優(yōu)點(diǎn): 1、一個(gè)調(diào)用者想創(chuàng)建一個(gè)對(duì)象,只要知道其名稱就可以了。
2、擴(kuò)展性高,如果想增加一個(gè)產(chǎn)品,只要擴(kuò)展一個(gè)工廠類就可以。
3、屏蔽產(chǎn)品的具體實(shí)現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口。
缺點(diǎn):每次增加一個(gè)產(chǎn)品時(shí),都需要增加一個(gè)具體類和對(duì)象實(shí)現(xiàn)工廠,使得系統(tǒng)中類的個(gè)數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,同時(shí)也增加了系統(tǒng)具體類的依賴。這
并不是什么好事。
1.2.實(shí)現(xiàn)(注:以下代碼均為不帶邏輯的實(shí)例代碼)
組成部分:
工廠類角色:這是本模式的核心,在此它會(huì)根據(jù)不同的產(chǎn)品選擇生產(chǎn)什么東西。
抽象產(chǎn)品角色:它一般是具體產(chǎn)品繼承的父類或者實(shí)現(xiàn)的接口。由接口或者抽象類來實(shí)現(xiàn)。
具體產(chǎn)品角色:工廠類所創(chuàng)建的對(duì)象就是此角色的實(shí)例。
首先定義一個(gè)接口(抽象產(chǎn)品角色):
public interface ISaveACDb { void SaveACDB(); }
根據(jù)產(chǎn)品定義各自的類(具體產(chǎn)品類)
public class SaveACDDbToBuChong : ISaveACDb { public bool SaveACDB() { return true; } } public class SaveACDDbToArchivesCases : ISaveACDb { public bool SaveACDB() { return true; } }
接口工廠類的定義:
public class SaveACDb_Factory { public static ISaveACDb Create_SaveACDb_Factory(string type) { ISaveACDb save = null; switch (type) { case "ArchivesCases": save = new SaveACDDbToArchivesCases(); break; case "BuChong": save = new SaveACDDbToBuChong(); break; } return save; } }
調(diào)用代碼:
public class WinformClientDbController : Controller { [HttpPost] public void SaveACInfo(string type) { var result = SaveACDb_Factory.Create_SaveACDb_Factory(type); result.SaveACDB(); } }
問:如果一直增加產(chǎn)品,是不是就要增加產(chǎn)品類?
答:是的。
有沒有發(fā)現(xiàn)問題,這樣不斷增加產(chǎn)品,然后增加產(chǎn)品類到時(shí)沒什么,但是相應(yīng)的回去修改工廠類,有沒有發(fā)現(xiàn),那么這樣就有問題,就像我上篇設(shè)計(jì)模式提到的“開閉原則”,我們?cè)?
這種模式下就充分的違背了,所以如果產(chǎn)品類如果會(huì)大量增加的話,你最起碼要知道這是違背設(shè)計(jì)原則的。
問:那該怎么解決呢?
答:用反射。
2.簡(jiǎn)單工廠與反射
反設(shè)我已經(jīng)在基礎(chǔ)拾遺------反射詳解介紹過來。
簡(jiǎn)單工廠中使用反射的目的就是去掉工廠類中的switch(或if)。ps:想一想這一改變,特別是我現(xiàn)在這種給其他客戶端提供接口的程序,大大第提高代碼的解耦。
代碼如下:
public class SaveACDb_Factory { public static ISaveACDb Create_SaveACDb_Factory(string obj, string className) { Assembly assembly = Assembly.GetExecutingAssembly(); // 獲取當(dāng)前程序集 var result = (ISaveACDb)assembly.CreateInstance("StrokeLocalWinformInterface" + ".SaveACDDbTo" + className); return result; } }
調(diào)用
[HttpPost] public void SaveACInfo(string obj, string userNickeName, string userToken, string className) { if (1 > 2)//驗(yàn)證usertoken return; var result = SaveACDb_Factory.Create_SaveACDb_Factory(obj, className); result.SaveACDB(obj); }
3.抽象工廠
就像上面說的,如果我們的產(chǎn)品不斷增加且成樹裝結(jié)構(gòu)增加,我們就要說說抽象工廠。
3.1.簡(jiǎn)介:
如果別人為你干啥去,你說你去吃飯去,但是你再去的過程當(dāng)中,如果考慮肯德基要吃雞翅還是漢堡,他們都是什么口味,去吃快餐都是有什么。。。。這樣如果選擇一次吃
飯,是不是要想半個(gè)小時(shí),所以去吃燴面這個(gè)產(chǎn)品也可以把它當(dāng)作吃飯這個(gè)超級(jí)工廠的子工廠。
抽象工廠就是圍繞這超級(jí)工廠建立的其他工廠。超級(jí)工廠是其他工廠的工廠。
優(yōu)點(diǎn):當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對(duì)象被設(shè)計(jì)成一起工作時(shí),它能保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象。
缺點(diǎn):產(chǎn)品族擴(kuò)展非常困難,要增加一個(gè)系列的某一產(chǎn)品,既要在抽象的 Creator 里加代碼,又要在具體的里面加代碼。
3.2.實(shí)現(xiàn):
抽象工廠角色: 這是工廠方法模式的核心,它與應(yīng)用程序無關(guān)。是具體工廠角色必須實(shí)現(xiàn)的接口或者必須繼承的父類。
具體工廠角色:它含有和具體業(yè)務(wù)邏輯有關(guān)的代碼。由應(yīng)用程序調(diào)用以創(chuàng)建對(duì)應(yīng)的具體產(chǎn)品的對(duì)象。
抽象產(chǎn)品角色:它是具體產(chǎn)品繼承的父類或者是實(shí)現(xiàn)的接口。
具體產(chǎn)品角色:具體工廠角色所創(chuàng)建的對(duì)象就是此角色的實(shí)例。
以下案例為借鑒過來的,就是公司老板有很多車,司機(jī)開車是一個(gè)超級(jí)工廠,每輛車是具體操作是另外一個(gè)工廠,這次偷個(gè)懶就不自己寫案例啦。
抽象產(chǎn)品:就是定一個(gè)車的類,此類有一個(gè)司機(jī)開車的方法抽象方法,和具體是什么車,進(jìn)行賦值的方法。
abstract class Car{ private String name; public abstract void drive(); public String getName() { return name; } public void setName(String name) { this.name = name; } }
具體產(chǎn)品:繼承抽象產(chǎn)品,寶馬和奔馳都是不同的車。
class Benz :Car{ public void drive(){ // } } class Bmw :Car{ public void drive(){ // } }
抽象工廠:司機(jī)就是要開車嗎。這個(gè)工廠抽象司機(jī)開車。
abstract class Driver{ public abstract Car createCar(String car) throws Exception; }
具體工廠:開寶馬和奔馳還是不一樣的,這個(gè)工廠針對(duì)不同的車去實(shí)例。
class BenzDriver :Driver{ public Car createCar(String car) throws Exception { return new Benz(); } } class BmwDriver :Driver{ public Car createCar(String car) throws Exception { return new Bmw(); } }
以上就是抽象工廠的組成部分,客戶端只需在實(shí)例化相應(yīng)的工廠調(diào)用即可。
調(diào)用代碼:
//老板 public class Boss{ public static void main(String[] args) throws Exception { Driver d = new BenzDriver(); Car c = d.createCar("benz"); c.setName("benz"); c.drive(); } }