C#設計模式(4)——抽象工廠模式

1、引言

在上一專題中介紹了工廠方法模式,工廠方法模式是爲了克服簡單工廠模式的缺點而設計出來的,簡單工廠模式的工廠類隨着產品類的增長鬚要增長額外的代碼),而工廠方法模式每一個具體工廠類只完成單個實例的建立,因此它具備很好的可擴展性。可是在現實生活中,一個工廠只建立單個產品這樣的例子不多,由於如今的工廠都多元化了,一個工廠建立一系列的產品,若是咱們要設計這樣的系統時,工廠方法模式顯然在這裏不適用,而後抽象工廠模式卻能夠很好地解決一系列產品建立的問題,這是本專題所要介紹的內容。html

2、抽象工廠詳細介紹

這裏首先以一個生活中抽象工廠的例子來實現一個抽象工廠,而後再給出抽象工廠的定義和UML圖來幫助你們更好地掌握抽象工廠模式,同時你們在理解的時候,能夠對照抽象工廠生活中例子的實現和它的定義來加深抽象工廠的UML圖理解。數據庫

2.1 抽象工廠的具體實現

下面就以生活中 「絕味」 連鎖店的例子來實現一個抽象工廠模式。例如,絕味鴨脖想在江西南昌和上海開分店,可是因爲當地人的口味不同,在南昌的全部絕味的東西會作的辣一點,而上海不喜歡吃辣的,因此上海的全部絕味的東西都不會作的像南昌的那樣辣,然而這點不一樣致使南昌絕味工廠和上海的絕味工廠生成全部絕味的產品都不一樣,也就是某個具體工廠須要負責一系列產品(指的是絕味全部食物)的建立工做,下面就具體看看如何使用抽象工廠模式來實現這種狀況。ide

  1 /// <summary>
  2     /// 下面以絕味鴨脖連鎖店爲例子演示下抽象工廠模式
  3     /// 由於每一個地方的喜歡的口味不同,有些地方喜歡辣點的,有些地方喜歡吃不辣點
  4     /// 客戶端調用
  5     /// </summary>
  6     class Client
  7     {
  8         static void Main(string[] args)
  9         {
 10             // 南昌工廠製做南昌的鴨脖和鴨架
 11             AbstractFactory nanChangFactory = new NanChangFactory();
 12             YaBo nanChangYabo = nanChangFactory.CreateYaBo();
 13             nanChangYabo.Print();
 14             YaJia nanChangYajia= nanChangFactory.CreateYaJia();
 15             nanChangYajia.Print();
 16 
 17             // 上海工廠製做上海的鴨脖和鴨架
 18             AbstractFactory shangHaiFactory = new ShangHaiFactory();
 19             shangHaiFactory.CreateYaBo().Print();
 20             shangHaiFactory.CreateYaJia().Print();
 21 
 22             Console.Read();
 23         }
 24     }
 25 
 26     /// <summary>
 27     /// 抽象工廠類,提供建立兩個不一樣地方的鴨架和鴨脖的接口
 28     /// </summary>
 29     public abstract class AbstractFactory
 30     {
 31         // 抽象工廠提供建立一系列產品的接口,這裏做爲例子,只給出了絕味中鴨脖和鴨架的建立接口
 32         public abstract YaBo CreateYaBo();
 33         public abstract YaJia CreateYaJia();
 34     }
 35 
 36     /// <summary>
 37     /// 南昌絕味工廠負責製做南昌的鴨脖和鴨架
 38     /// </summary>
 39     public class NanChangFactory : AbstractFactory
 40     {
 41         // 製做南昌鴨脖
 42         public override YaBo CreateYaBo()
 43         {
 44             return new NanChangYaBo();
 45         }
 46         // 製做南昌鴨架
 47         public override YaJia CreateYaJia()
 48         {
 49             return new NanChangYaJia();
 50         }
 51     }
 52 
 53     /// <summary>
 54     /// 上海絕味工廠負責製做上海的鴨脖和鴨架
 55     /// </summary>
 56     public class ShangHaiFactory : AbstractFactory
 57     {
 58         // 製做上海鴨脖
 59         public override YaBo CreateYaBo()
 60         {
 61             return new ShangHaiYaBo();
 62         }
 63         // 製做上海鴨架
 64         public override YaJia CreateYaJia()
 65         {
 66             return new ShangHaiYaJia();
 67         }
 68     }
 69 
 70     /// <summary>
 71     /// 鴨脖抽象類,供每一個地方的鴨脖類繼承
 72     /// </summary>
 73     public abstract class YaBo
 74     {
 75         /// <summary>
 76         /// 打印方法,用於輸出信息
 77         /// </summary>
 78         public abstract void Print();
 79     }
 80 
 81     /// <summary>
 82     /// 鴨架抽象類,供每一個地方的鴨架類繼承
 83     /// </summary>
 84     public abstract class YaJia
 85     {
 86         /// <summary>
 87         /// 打印方法,用於輸出信息
 88         /// </summary>
 89         public abstract void Print();
 90     }
 91 
 92     /// <summary>
 93     /// 南昌的鴨脖類,由於江西人喜歡吃辣的,因此南昌的鴨脖稍微會比上海作的辣
 94     /// </summary>
 95     public class NanChangYaBo : YaBo
 96     {
 97         public override void Print()
 98         {
 99             Console.WriteLine("南昌的鴨脖");
100         }
101     }
102 
103     /// <summary>
104     /// 上海的鴨脖沒有南昌的鴨脖作的辣
105     /// </summary>
106     public class ShangHaiYaBo : YaBo
107     {
108         public override void Print()
109         {
110             Console.WriteLine("上海的鴨脖");
111         }
112     }
113 
114     /// <summary>
115     /// 南昌的鴨架
116     /// </summary>
117     public class NanChangYaJia : YaJia
118     {
119         public override void Print()
120         {
121             Console.WriteLine("南昌的鴨架子");
122         }
123     }
124 
125     /// <summary>
126     /// 上海的鴨架
127     /// </summary>
128     public class ShangHaiYaJia : YaJia
129     {
130         public override void Print()
131         {
132             Console.WriteLine("上海的鴨架子");
133         }
134     }

2.2 抽象工廠模式的定義和類圖

上面代碼中都有詳細的註釋,這裏就再也不解釋上面的代碼了,下面就具體看看抽象工廠模式的定義吧(理解定義能夠參考上面的實現來加深理解):函數

抽象工廠模式:提供一個建立產品的接口來負責建立相關或依賴的對象,而不具體明確指定具體類工具

抽象工廠容許客戶使用抽象的接口來建立一組相關產品,而不須要知道或關心實際生產出的具體產品是什麼。這樣客戶就能夠從具體產品中被解耦。下面經過抽象工模式的類圖來了解各個類中之間的關係:ui

2.3 抽象工廠應對需求變動

看完上面抽象工廠的實現以後,若是 「絕味」公司又想在湖南開一家分店怎麼辦呢? 由於湖南人喜歡吃麻辣的,下面就具體看看應用了抽象工廠模式的系統是如何應對這種需求的。spa

/// <summary>
    /// 若是絕味又想開一家湖南的分店時,由於湖南喜歡吃麻的
    /// 因此這是有須要有一家湖南的工廠專門製做
    /// </summary>
    public class HuNanFactory : AbstractFactory
    {
        // 製做湖南鴨脖
        public override YaBo CreateYaBo()
        {
            return new HuNanYaBo();
        }

        // 製做湖南鴨架
        public override YaJia CreateYaJia()
        {
            return new HuNanYajia();
        }
    }

    /// <summary>
    /// 湖南的鴨脖
    /// </summary>
    public class HuNanYaBo : YaBo
    {
        public override void Print()
        {
            Console.WriteLine("湖南的鴨脖");
        }
    }

    /// <summary>
    /// 湖南的鴨架
    /// </summary>
    public class HuNanYajia : YaJia
    {
        public override void Print()
        {
            Console.WriteLine("湖南的鴨架子");
        }
    }

此時,只須要添加三個類:一個是湖南具體工廠類,負責建立湖南口味的鴨脖和鴨架,另外兩個類是具備湖南口味的鴨脖類和鴨架類。從上面代碼看出,抽象工廠對於系列產品的變化支持 「開放——封閉」原則(指的是要求系統對擴展開放,對修改封閉),擴展起來很是簡便,可是,抽象工廠對於添加新產品這種狀況就不支持」開放——封閉 「原則,這也是抽象工廠的缺點所在,這點會在第四部分詳細介紹。設計

3、抽象工廠的分析

抽象工廠模式將具體產品的建立延遲到具體工廠的子類中,這樣將對象的建立封裝起來,能夠減小客戶端與具體產品類之間的依賴,從而使系統耦合度低,這樣更有利於後期的維護和擴展,這真是抽象工廠模式的優勢所在,而後抽象模式同時也存在不足的地方。下面就具體看下抽象工廠的缺點(缺點其實在前面的介紹中以已經涉及了):code

抽象工廠模式很難支持新種類產品的變化。這是由於抽象工廠接口中已經肯定了能夠被建立的產品集合,若是須要添加新產品,此時就必須去修改抽象工廠的接口,這樣就涉及到抽象工廠類的以及全部子類的改變,這樣也就違背了「開發——封閉」原則。htm

知道了抽象工廠的優缺點以後,也就能很好地把握什麼狀況下考慮使用抽象工廠模式了,下面就具體看看使用抽象工廠模式的系統應該符合那幾個前提:

  • 一個系統不要求依賴產品類實例如何被建立、組合和表達的表達,這點也是全部工廠模式應用的前提。
  • 這個系統有多個系列產品,而系統中只消費其中某一系列產品
  • 系統要求提供一個產品類的庫,全部產品以一樣的接口出現,客戶端不須要依賴具體實現。

4、.NET中抽象工廠模式實現

抽象工廠模式在實際中的應用也是至關頻繁的,然而在咱們.NET類庫中也存在應用抽象工廠模式的類,這個類就是System.Data.Common.DbProviderFactory,這個類位於System.Data.dll程序集中,該類扮演抽象工廠模式中抽象工廠的角色,咱們能夠用reflector反編譯工具查看該類的實現:

/// 扮演抽象工廠的角色
/// 建立鏈接數據庫時所須要的對象集合,
/// 這個對象集合包括有 DbConnection對象(這個是抽象產品類,如絕味例子中的YaBo類)、DbCommand類、DbDataAdapter類,針對不一樣的具體工廠都須要實現該抽象類中方法,
public abstract class DbProviderFactory
{
    // 提供了建立具體產品的接口方法
    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類是一個抽象工廠類,該類提供了建立數據庫鏈接時所須要的對象集合的接口,實際建立的工做在其子類工廠中進行,微軟使用的是SQL Server數據庫,所以提供了鏈接SQL Server數據的具體工廠實現,具體代碼能夠用反編譯工具查看,具體代碼以下:

/// 扮演着具體工廠的角色,用來建立鏈接SQL Server數據所須要的對象
public sealed class SqlClientFactory : DbProviderFactory, IServiceProvider
{
    // Fields
    public static readonly SqlClientFactory Instance = new SqlClientFactory();

   // 構造函數
    private SqlClientFactory()
    {
    }
    
   // 重寫抽象工廠中的方法
    public override DbCommand CreateCommand()
    {  // 建立具體產品
        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的具體工廠的實現,咱們也能夠自定義鏈接Oracle、MySql的具體工廠的實現。

5、總結

到這裏,抽象工廠模式的介紹就結束,在下一專題就將爲你們介紹建造模式。

相關文章
相關標籤/搜索