在上一專題中介紹了工廠方法模式,工廠方法模式是為了克服簡單工廠模式的缺點而設(shè)計出來的,簡單工廠模式的工廠類隨著產(chǎn)品類的增加需要增加額外的代碼),而工廠方法模式每個具體工廠類只完成單個實例的創(chuàng)建,所以它具有很好的可擴展性。但是在現(xiàn)實生活中,一個工廠只創(chuàng)建單個產(chǎn)品這樣的例子很少,因為現(xiàn)在的工廠都多元化了,一個工廠創(chuàng)建一系列的產(chǎn)品,如果我們要設(shè)計這樣的系統(tǒng)時,工廠方法模式顯然在這里不適用,然后抽象工廠模式卻可以很好地解決一系列產(chǎn)品創(chuàng)建的問題,這是本專題所要介紹的內(nèi)容。
這里首先以一個生活中抽象工廠的例子來實現(xiàn)一個抽象工廠,然后再給出抽象工廠的定義和UML圖來幫助大家更好地掌握抽象工廠模式,同時大家在理解的時候,可以對照抽象工廠生活中例子的實現(xiàn)和它的定義來加深抽象工廠的UML圖理解。
下面就以生活中 “絕味” 連鎖店的例子來實現(xiàn)一個抽象工廠模式。例如,絕味鴨脖想在江西南昌和上海開分店,但是由于當(dāng)?shù)厝说目谖恫灰粯?,在南昌的所有絕味的東西會做的辣一點,而上海不喜歡吃辣的,所以上海的所有絕味的東西都不會做的像南昌的那樣辣,然而這點不同導(dǎo)致南昌絕味工廠和上海的絕味工廠生成所有絕味的產(chǎn)品都不同,也就是某個具體工廠需要負責(zé)一系列產(chǎn)品(指的是絕味所有食物)的創(chuàng)建工作,下面就具體看看如何使用抽象工廠模式來實現(xiàn)這種情況。
////// 下面以絕味鴨脖連鎖店為例子演示下抽象工廠模式 /// 因為每個地方的喜歡的口味不一樣,有些地方喜歡辣點的,有些地方喜歡吃不辣點 /// 客戶端調(diào)用 /// class Client { static void Main(string[] args) { // 南昌工廠制作南昌的鴨脖和鴨架 AbstractFactory nanChangFactory = new NanChangFactory(); YaBo nanChangYabo = nanChangFactory.CreateYaBo(); nanChangYabo.Print(); YaJia nanChangYajia= nanChangFactory.CreateYaJia(); nanChangYajia.Print(); // 上海工廠制作上海的鴨脖和鴨架 AbstractFactory shangHaiFactory = new ShangHaiFactory(); shangHaiFactory.CreateYaBo().Print(); shangHaiFactory.CreateYaJia().Print(); Console.Read(); } } ////// 抽象工廠類,提供創(chuàng)建兩個不同地方的鴨架和鴨脖的接口 /// public abstract class AbstractFactory { // 抽象工廠提供創(chuàng)建一系列產(chǎn)品的接口,這里作為例子,只給出了絕味中鴨脖和鴨架的創(chuàng)建接口 public abstract YaBo CreateYaBo(); public abstract YaJia CreateYaJia(); } ////// 南昌絕味工廠負責(zé)制作南昌的鴨脖和鴨架 /// public class NanChangFactory : AbstractFactory { // 制作南昌鴨脖 public override YaBo CreateYaBo() { return new NanChangYaBo(); } // 制作南昌鴨架 public override YaJia CreateYaJia() { return new NanChangYaJia(); } } ////// 上海絕味工廠負責(zé)制作上海的鴨脖和鴨架 /// public class ShangHaiFactory : AbstractFactory { // 制作上海鴨脖 public override YaBo CreateYaBo() { return new ShangHaiYaBo(); } // 制作上海鴨架 public override YaJia CreateYaJia() { return new ShangHaiYaJia(); } } ////// 鴨脖抽象類,供每個地方的鴨脖類繼承 /// public abstract class YaBo { ////// 打印方法,用于輸出信息 /// public abstract void Print(); } ////// 鴨架抽象類,供每個地方的鴨架類繼承 /// public abstract class YaJia { ////// 打印方法,用于輸出信息 /// public abstract void Print(); } ////// 南昌的鴨脖類,因為江西人喜歡吃辣的,所以南昌的鴨脖稍微會比上海做的辣 /// public class NanChangYaBo : YaBo { public override void Print() { Console.WriteLine("南昌的鴨脖"); } } ////// 上海的鴨脖沒有南昌的鴨脖做的辣 /// public class ShangHaiYaBo : YaBo { public override void Print() { Console.WriteLine("上海的鴨脖"); } } ////// 南昌的鴨架 /// public class NanChangYaJia : YaJia { public override void Print() { Console.WriteLine("南昌的鴨架子"); } } ////// 上海的鴨架 /// public class ShangHaiYaJia : YaJia { public override void Print() { Console.WriteLine("上海的鴨架子"); } }
上面代碼中都有詳細的注釋,這里就不再解釋上面的代碼了,下面就具體看看抽象工廠模式的定義吧(理解定義可以參考上面的實現(xiàn)來加深理解):
抽象工廠模式:提供一個創(chuàng)建產(chǎn)品的接口來負責(zé)創(chuàng)建相關(guān)或依賴的對象,而不具體明確指定具體類
抽象工廠允許客戶使用抽象的接口來創(chuàng)建一組相關(guān)產(chǎn)品,而不需要知道或關(guān)心實際生產(chǎn)出的具體產(chǎn)品是什么。這樣客戶就可以從具體產(chǎn)品中被解耦。下面通過抽象工模式的類圖來了解各個類中之間的關(guān)系:
看完上面抽象工廠的實現(xiàn)之后,如果 “絕味”公司又想在湖南開一家分店怎么辦呢? 因為湖南人喜歡吃麻辣的,下面就具體看看應(yīng)用了抽象工廠模式的系統(tǒng)是如何應(yīng)對這種需求的。
////// 如果絕味又想開一家湖南的分店時,因為湖南喜歡吃麻的 /// 所以這是有需要有一家湖南的工廠專門制作 /// public class HuNanFactory : AbstractFactory { // 制作湖南鴨脖 public override YaBo CreateYaBo() { return new HuNanYaBo(); } // 制作湖南鴨架 public override YaJia CreateYaJia() { return new HuNanYajia(); } } ////// 湖南的鴨脖 /// public class HuNanYaBo : YaBo { public override void Print() { Console.WriteLine("湖南的鴨脖"); } } ////// 湖南的鴨架 /// public class HuNanYajia : YaJia { public override void Print() { Console.WriteLine("湖南的鴨架子"); } }
此時,只需要添加三個類:一個是湖南具體工廠類,負責(zé)創(chuàng)建湖南口味的鴨脖和鴨架,另外兩個類是具有湖南口味的鴨脖類和鴨架類。從上面代碼看出,抽象工廠對于系列產(chǎn)品的變化支持 “開放——封閉”原則(指的是要求系統(tǒng)對擴展開放,對修改封閉),擴展起來非常簡便,但是,抽象工廠對于添加新產(chǎn)品這種情況就不支持”開放——封閉 “原則,這也是抽象工廠的缺點所在,這點會在第四部分詳細介紹。
抽象工廠模式將具體產(chǎn)品的創(chuàng)建延遲到具體工廠的子類中,這樣將對象的創(chuàng)建封裝起來,可以減少客戶端與具體產(chǎn)品類之間的依賴,從而使系統(tǒng)耦合度低,這樣更有利于后期的維護和擴展,這真是抽象工廠模式的優(yōu)點所在,然后抽象模式同時也存在不足的地方。下面就具體看下抽象工廠的缺點(缺點其實在前面的介紹中以已經(jīng)涉及了):
抽象工廠模式很難支持新種類產(chǎn)品的變化。這是因為抽象工廠接口中已經(jīng)確定了可以被創(chuàng)建的產(chǎn)品集合,如果需要添加新產(chǎn)品,此時就必須去修改抽象工廠的接口,這樣就涉及到抽象工廠類的以及所有子類的改變,這樣也就違背了“開發(fā)——封閉”原則。
知道了抽象工廠的優(yōu)缺點之后,也就能很好地把握什么情況下考慮使用抽象工廠模式了,下面就具體看看使用抽象工廠模式的系統(tǒng)應(yīng)該符合那幾個前提:
一個系統(tǒng)不要求依賴產(chǎn)品類實例如何被創(chuàng)建、組合和表達的表達,這點也是所有工廠模式應(yīng)用的前提。
這個系統(tǒng)有多個系列產(chǎn)品,而系統(tǒng)中只消費其中某一系列產(chǎn)品
系統(tǒng)要求提供一個產(chǎn)品類的庫,所有產(chǎn)品以同樣的接口出現(xiàn),客戶端不需要依賴具體實現(xiàn)。
抽象工廠模式在實際中的應(yīng)用也是相當(dāng)頻繁的,然而在我們.NET類庫中也存在應(yīng)用抽象工廠模式的類,這個類就是System.Data.Common.DbProviderFactory,這個類位于System.Data.dll程序集中,該類扮演抽象工廠模式中抽象工廠的角色,我們可以用reflector反編譯工具查看該類的實現(xiàn):
/// 扮演抽象工廠的角色 /// 創(chuàng)建連接數(shù)據(jù)庫時所需要的對象集合, /// 這個對象集合包括有 DbConnection對象(這個是抽象產(chǎn)品類,如絕味例子中的YaBo類)、DbCommand類、DbDataAdapter類,針對不同的具體工廠都需要實現(xiàn)該抽象類中方法, public abstract class DbProviderFactory { // 提供了創(chuàng)建具體產(chǎn)品的接口方法 protected DbProviderFactory(); public virtual DbCommand CreateCommand(); public virtual DbCommandBuilder CreateCommandBuilder(); public virtual DbConnection CreateConnection(); public virtual DbConnectionStringBuilder CreateConnectionStringBuilder(); public virtual DbDataAdapter CreateDataAdapter(); public virtual DbDataSourceEnumerator CreateDataSourceEnumerator(); public virtual DbParameter CreateParameter(); public virtual CodeAccessPermission CreatePermission(PermissionState state); }
DbProviderFactory類是一個抽象工廠類,該類提供了創(chuàng)建數(shù)據(jù)庫連接時所需要的對象集合的接口,實際創(chuàng)建的工作在其子類工廠中進行,微軟使用的是SQL Server數(shù)據(jù)庫,因此提供了連接SQL Server數(shù)據(jù)的具體工廠實現(xiàn),具體代碼可以用反編譯工具查看,具體代碼如下:
/// 扮演著具體工廠的角色,用來創(chuàng)建連接SQL Server數(shù)據(jù)所需要的對象 public sealed class SqlClientFactory : DbProviderFactory, IServiceProvider { // Fields public static readonly SqlClientFactory Instance = new SqlClientFactory(); // 構(gòu)造函數(shù) private SqlClientFactory() { } // 重寫抽象工廠中的方法 public override DbCommand CreateCommand() { // 創(chuàng)建具體產(chǎn)品 return new SqlCommand(); } public override DbCommandBuilder CreateCommandBuilder() { return new SqlCommandBuilder(); } public override DbConnection CreateConnection() { return new SqlConnection(); } public override DbConnectionStringBuilder CreateConnectionStringBuilder() { return new SqlConnectionStringBuilder(); } public override DbDataAdapter CreateDataAdapter() { return new SqlDataAdapter(); } public override DbDataSourceEnumerator CreateDataSourceEnumerator() { return SqlDataSourceEnumerator.Instance; } public override DbParameter CreateParameter() { return new SqlParameter(); } public override CodeAccessPermission CreatePermission(PermissionState state) { return new SqlClientPermission(state); } }
因為微軟只給出了連接SQL Server的具體工廠的實現(xiàn),我們也可以自定義連接Oracle、MySql的具體工廠的實現(xiàn)。
到這里,抽象工廠模式的介紹就結(jié)束,在下一專題就將為大家介紹建造模式。
附件:http://down.51cto.com/data/2363510創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機房獨有T級流量清洗系統(tǒng)配攻擊溯源,準確進行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務(wù)器買多久送多久。