前言

兩個(gè)月前寫(xiě)過(guò)一次設(shè)計(jì)模式系列,但很不滿意就刪除了。顯然希望能做到學(xué)以致用,而非看書(shū)總結(jié),設(shè)計(jì)模式絕對(duì)是你解決問(wèn)題的一個(gè)思路,但在這有點(diǎn)自己的小建議,設(shè)計(jì)模式

并不是用作提高你代碼的效率,用它的目的只是讓你的代碼看起來(lái)更規(guī)范,更易擴(kuò)展與維護(hù)。所以有的時(shí)候你站在你自身需要去選擇要不要使用設(shè)計(jì)模式。上周工作當(dāng)中有一個(gè)需求

正好是適合用工廠模式來(lái)解決的,所以就在這給大家討論討論工廠模式吧。

1.簡(jiǎn)單工廠模式

在工廠模式中,我們?cè)趧?chuàng)建對(duì)象時(shí)不會(huì)對(duì)客戶端暴露創(chuàng)建邏輯,并且是通過(guò)使用一個(gè)共同的接口來(lái)指向新創(chuàng)建的對(duì)象。

比如說(shuō),我要給其他終端提供保存實(shí)例的接口,但是實(shí)例卻用很多個(gè),這時(shí)提供的接口,如果每個(gè)實(shí)例都提供一邊,就會(huì)變成這樣提供多個(gè)端口,如果要增加就要繼續(xù)提供接口,故

此我就想到了用工廠模式。

1.1.簡(jiǎn)介:

就好比中午你下樓去吃飯,別人問(wèn)你干啥去?你說(shuō)我去吃黃燜雞,我去吃燴面,我去吃肯德基,去吃麻辣燙。。。。這些好像沒(méi)錯(cuò),但是估計(jì)你不會(huì)這么回答,你一般都是回答

我去吃飯。這就是工廠模式要走的,具體你要吃什么東西,不用告訴別人,別人問(wèn)的主題是你去干什么,你告訴他你娶吃飯就行,具體你要吃什么,是你自己的決定,無(wú)需說(shuō)出來(lái)。

優(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)的接口。由接口或者抽象類來(lái)實(shí)現(xiàn)。

具體產(chǎn)品角色:工廠類所創(chuàng)建的對(duì)象就是此角色的實(shí)例。

首先定義一個(gè)接口(抽象產(chǎn)品角色):

public interface ISaveACDb
    { void SaveACDB();
    }

根據(jù)產(chǎn)品定義各自的類(具體產(chǎn)品類)

復(fù)制代碼
  public class SaveACDDbToBuChong : ISaveACDb
    { public bool SaveACDB()
        { return true;
        }
    } public class SaveACDDbToArchivesCases : ISaveACDb
    { public bool SaveACDB()
        { return true;
        }
    }
復(fù)制代碼

接口工廠類的定義:

復(fù)制代碼
  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;
        }
    }
復(fù)制代碼

調(diào)用代碼:

復(fù)制代碼
 public class WinformClientDbController : Controller
    {
        [HttpPost] public void SaveACInfo(string type)
        { var result = SaveACDb_Factory.Create_SaveACDb_Factory(type);
            result.SaveACDB();
        }
    }
復(fù)制代碼

問(wèn):如果一直增加產(chǎn)品,是不是就要增加產(chǎn)品類?

答:是的。

有沒(méi)有發(fā)現(xiàn)問(wèn)題,這樣不斷增加產(chǎn)品,然后增加產(chǎn)品類到時(shí)沒(méi)什么,但是相應(yīng)的回去修改工廠類,有沒(méi)有發(fā)現(xiàn),那么這樣就有問(wèn)題,就像我上篇設(shè)計(jì)模式提到的“開(kāi)閉原則”,我們?cè)?

這種模式下就充分的違背了,所以如果產(chǎn)品類如果會(huì)大量增加的話,你最起碼要知道這是違背設(shè)計(jì)原則的。

問(wèn):那該怎么解決呢?

答:用反射。

2.簡(jiǎn)單工廠與反射

反設(shè)我已經(jīng)在基礎(chǔ)拾遺------反射詳解介紹過(guò)來(lái)。

簡(jiǎn)單工廠中使用反射的目的就是去掉工廠類中的switch(或if)。ps:想一想這一改變,特別是我現(xiàn)在這種給其他客戶端提供接口的程序,大大第提高代碼的解耦。

代碼如下:

復(fù)制代碼
  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;
        }
    }
復(fù)制代碼

調(diào)用

復(fù)制代碼
 [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);
        }
復(fù)制代碼

 

3.抽象工廠

就像上面說(shuō)的,如果我們的產(chǎn)品不斷增加且成樹(shù)裝結(jié)構(gòu)增加,我們就要說(shuō)說(shuō)抽象工廠。

3.1.簡(jiǎn)介:

如果別人為你干啥去,你說(shuō)你去吃飯去,但是你再去的過(guò)程當(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)用程序無(wú)關(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í)例。

以下案例為借鑒過(guò)來(lái)的,就是公司老板有很多車,司機(jī)開(kāi)車是一個(gè)超級(jí)工廠,每輛車是具體操作是另外一個(gè)工廠,這次偷個(gè)懶就不自己寫(xiě)案例啦。

抽象產(chǎn)品:就是定一個(gè)車的類,此類有一個(gè)司機(jī)開(kāi)車的方法抽象方法,和具體是什么車,進(jìn)行賦值的方法。

復(fù)制代碼
 abstract class Car{ private String name; public abstract void drive(); public String getName() { return name;  
        } public void setName(String name) { this.name = name;  
        }  
    } 

復(fù)制代碼

具體產(chǎn)品:繼承抽象產(chǎn)品,寶馬和奔馳都是不同的車。

復(fù)制代碼
 class Benz :Car{ public void drive(){  
           // }  
    } class Bmw :Car{ public void drive(){  
           
//  }  
    } 

復(fù)制代碼

抽象工廠:司機(jī)就是要開(kāi)車嗎。這個(gè)工廠抽象司機(jī)開(kāi)車。

abstract class Driver{ public abstract Car createCar(String car) throws Exception;  
    } 

具體工廠:開(kāi)寶馬和奔馳還是不一樣的,這個(gè)工廠針對(duì)不同的車去實(shí)例。

復(fù)制代碼
    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();  
        }  
    } 
復(fù)制代碼

以上就是抽象工廠的組成部分,客戶端只需在實(shí)例化相應(yīng)的工廠調(diào)用即可。

調(diào)用代碼:

復(fù)制代碼
//老板  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();  
        }  
    }
復(fù)制代碼