系統架構技能之設計模式—工廠模式
一、開篇
本文主要是講述設計模式中最經典的創建型模式-工廠模式,本文將會從以下幾點對工廠模式進行闡述。 本文將會從上面的四個方面進行詳細的講解和說明,當然會的朋友可以之處我的不足之處,不會的朋友也請我們能夠相互學習討論。
二、摘要
本文將會主要是結合項目中的一些實例作為實例來分析工程模式的使用方式和何時使用工程模式,并且分析工程模式的有點和它解決的問題,在我們實際的項目中何時能使用到它,或者說我們在什么情況下,應該考慮使用工廠模式來解決項目中的問題,一般情況下我們可以這樣理解設計模式,設計模式是一種方案,為我們遇到與設計模式提出的應用場景想象或者相仿的場景中,這類問題通常是經常發生或者是經常遇到的問題的通用解決方案。
本文依然是采用圖文講解的形式來分析工程模式在項目中出現的位置,并且給出幾個靈活的實現方案。主要針對的實現方式有:通過配置文件,通過類型,通過委托,通過特性等來實現工廠。
三、本文大綱
a、開篇。
b、摘要。
c、本文大綱。
d、工廠模式的特點及使用場景。
e、工廠模式的實現方案。
f、工廠模式使用總結。
g、系列進度。
h、下篇預告。
四、工廠模式的特點及使用場景
4.1、工廠模式簡介
工廠模式是創建型模式中最典型的模式,主要是用來創建對象,減少我們在使用某個對象時的new() 操作,我相信大家都有這樣的困惑,目前我所在的項目都在程序開發的過程中,還是有很多的new()操作出現在表現層中,并沒有通過工廠來創建對象,一方面可能是因為我們自身比較懶,不規范項目的編碼形式,另外一方面也是由于項目的進度比較緊,沒有那么多的時間去完成工廠的統一創建,當然對于這樣的動態創建對象的工廠,推薦的做法還是我們后面會講到的創建型模式--《抽象工廠模式》來解決吧。
如果您并不知道工廠模式是用來干什么的,我們可以通過如下舉例來說明,例如我們現在有個礦泉水加工廠,加工礦泉水,我們現在知道有礦泉水這個對象,那么當我批量生產礦泉水的時候,我們就通過工廠來批量的生產,等于我們程序中的批量創建對象。這時候我有很多個對象,也就是很多游客,他們每人都要一瓶礦泉水,這時候如果說把游客比作不同的應用程序模塊,都要使用礦泉水這個對象,那么我是不是應該每個應用程序都在使用這個對象的時候,我使用new()操作呢?,無疑這不是一個好的方案。我們來看看圖形化的描述吧?
這種情況下,不同的游客需要礦泉水的時候,我就new()一個礦泉水和我找個加工廠生產礦泉水明顯是有差別的,這個時候,游客不應該和礦泉水有關聯關系了,而且游客不知道,礦泉水是怎么生產出來的,也不需要關心這些東西。
那么我們應該如何去解決這樣的問題呢?基于面向對象的變成設計時,原則就是低耦合,對象和對象之間。那么對象之間的引用關系,可以通過抽象出接口,通過借口的依賴來解耦,降低系統的耦合性。 假如這個時候我修改對象服務的名稱,那么我是不是必須把所有的調用這個對象服務應用程序代碼都進行修改?這個是必須的,否則程序無法編譯通過的。但是如果我們使用工廠模式的時候呢?有什么不同呢?我們來看看:
上面是添加了工廠模式之后的情況,上面就算是你修改了類名之后,只需要修改工廠中的New出來的類即可,當然如果你要是通過返回接口的形式的話,再不修改接口命名的前提下,如何修改類方法都是可行的,并且通過工廠模式,無疑降低了應用程序與對象之間的耦合性,通過工廠來解耦,提供程序的應對變化的適應能力。
4.2、工廠模式的使用場景
工廠模式一般用于創建一類對象,而不用每次在使用時通過new()對象才能使用對象,而是通過工廠來完成對象的創建,這樣不但提供了統一創建對象的入口,而且對于程序的可維護和可測試性都有很大的提高。總體來說如下場景使用工廠模式非常合適:
1、工廠負責創建某一類對象的時候,或者說工廠的職責比較單一時,如果說多個類型的對象時候,用工廠模式就不如使用抽象工廠了
2、一般比較少的積累對象,可以通過類型的判定創建不同的對象時,也是可以通過工廠模式來完成,例如多數據庫的支持,我們在設計數據訪問層時,利用簡單對象工廠,通過枚舉或者配置文件的形式,來動態的創建數據訪問層實例。
3、一般來說類型單一的對象,或者類型比較少的時候,使用工廠模式來創建對象可以解決一類問題。還可以通過一個總的工廠,來創建多個工廠,然后多個工廠負責創建相應的實例,有點類似我們平時說的目錄結構似的。
類似如下的形式,大家一看就明白了: 等于是不同層級的工廠,具有不同的職責和任務。
五、工廠模式的實現方案
5.1、工廠模式的配置文件實現。
我們先看配置文件的配置內容:
<ConnKey>default</ConnKey>
<DataBaseType>MSSQLServer</DataBaseType>
</DatabaseInfo>
定義要創建的對象實例統一接口:
/// 所有的數據訪問接口
/// </summary>
public interface IDbAccess
{
}
實現這個接口的具體類:
{
//相關的方法
public System.Data.SqlClient.SqlConnection Connection
{
get
{
return new System.Data.SqlClient.SqlConnection();
}
}
}
負責創建返回類型為IDbAccess的數據訪問層對象實例:
{
public IDbAccess Create()
{
IDbAccess instance = null;
System.Xml.XmlDocument doc=new System.Xml.XmlDocument();
doc.LoadXml("");
XmlElement root = doc.DocumentElement;//XML文檔的根節點
XmlNode node = root.SelectSingleNode("DataBaseType");
switch (node.InnerText)
{
case "SQLServer":
instance = new SQLServer();
break;
case "Oracle":
instance = new Oracle();
break;
default:
break;
}
return instance;
}
}
具體的控制臺輸出測試代碼如下:
{
static void Main(string[] args)
{
DBFactory factory = new DBFactory();
IDbAccess dbaccess = factory.Create();
//使用相應的數據訪問對象即可。
}
}
5.2、通過枚舉來實現。
通過枚舉來實現后,工廠類的創建代碼如下:
{
public IDbAccess CreateByEnum(DbType dbType)
{
IDbAccess dbAccess = null;
switch ((int)dbType)
{
case (int)DbType.SQLServer:
dbAccess= new SQLServer();
break;
case (int)DbType.Oracle:
dbAccess = new Oracle();
break;
case (int)DbType.Access:
dbAccess = new Access();
break;
default:
break;
}
return dbAccess;
}
}
相應的枚舉代碼如下:
{
SQLServer=0,
Oracle=1,
Access=2
}
相應的控制臺測試代碼:
{
DBFactory factory = new DBFactory();
IDbAccess dbaccess = factory.CreateByEnum(DbType.SQLServer);
//使用相應的數據訪問對象即可。
}
5.3、工廠模式的復雜進階
我們上面只是定義了一種工廠,該工廠負責所有的子類對象的創建,如果說我們的工廠要求能夠滿足增加新的對象時,我們必須修改工廠代碼,那么我們如何來做呢?我們可以這樣來做。
每個類型的對象都有與這個類型對應的工廠去創建,那么就算以后增加或者修改,只需要修改相應的工廠涉及的文件即可。但是這樣也有很大的弊端就是工廠類太多,難以維護。優點是支持動態的增加新的對象類型,對之前的創建工作不會造成影響,我們來看看相應的代碼,基于圖中的幾個類型。先定義對象的統一接口和工廠的接口。先看對象接口的統一定義:
{
/// <summary>
/// 重要級別
/// </summary>
/// <returns></returns>
int ImportLevel();
}
工廠接口的統一定義:
{
IComObject Create();
}
我們來看看具體的對象實現和工廠實現吧,我們這里以上圖中的書為例說明創建過程:
{
public IComObject Create()
{
return new Book();
}
}
具體的對象實現代碼-實現IComObject對象接口:
{
public int ImportLevel()
{
return 0;
}
}
我們來看看具體的程序調用代碼:
{
IComFactory factory = new BookFactory();
IComObject book = factory.Create();
//使用相應的數據訪問對象即可。
}
通過上面的形式,我們可以看到,后期如果新增比如說我現在要對個產品這個對象新增到系統中,那么我們只需要增加相應的對象實現類和工廠實現類即可,對其他地方不會有影響,相比上面講述的,一個工廠創建所有的對象實例的方式無疑提供了新增對象類型創建的能力。
六、工廠模式使用總結
通過上面的簡單實例講解,估計高手理解起來很容易也很簡單,其實本來也是很簡單的,大伙不了解工廠模式的朋友,應該也能理解講述的內容,本文前面講述的2中方式主要是針對簡單工廠模式,簡單工廠模式,不符合高內聚的原則,因為所有的對象的創建工作都放在一個類的內部去完成,邏輯太復雜了,通過后面的工廠模式,將每個工廠的職責進行了更細化,每個工廠只負責具體對象類型實例的創建。這也為后期增加新的對象類型提供了不錯的擴展,本文并沒有給出特性+委托的工廠的實現方案,我放在下篇的抽象工廠中去講解,也會針對配置文件,特性,委托的幾種方式來給出抽象工廠模式的實現方案,當然我給出的都是很簡單的例子,希望大家一看就懂,就能用在實際的項目中,可能高手會認為我講的太淺了,一方面是因為自己沒有整理好思路,時間緊迫,另一方面是因為自身能力有限,還請大家多提寶貴意見,我們總結下本文講述的內容吧;
前面講述了2中簡單工廠模式的實現方案。通過配置文件、通過枚舉來完成對象的創建,其實就是根據對象的類型來完成,也可以通過反射來完成。這里給出簡單的實現:
{
Type type = Type.GetType(TypeName);
IDbAccess obj = (IDbAccess)Activator.CreateInstance(type);
return obj;
}
其實就是這樣的簡短代碼,給出關鍵代碼實現吧,可能實際運行中還要進行相應的調整。總體來說簡單工廠適合項目中類型不多的情況時使用簡單工廠很方便。當項目中頻繁的增加不同類型的對象時,考慮使用工廠模式,來滿足這樣的動態變化需求。