1. 程式人生 > >設計模式學習筆記-抽象工廠模式

設計模式學習筆記-抽象工廠模式

工廠方法模式是為了克服簡單工廠模式的缺點而設計出來的,簡單工廠模式的工廠類隨著產品類的增加需要增加額外的程式碼),而工廠方法模式每個具體工廠類只完成單個例項的建立,所以它具有很好的可擴充套件性。。但是在現實生活中,一個工廠只建立單個產品這樣的例子很少

定義:

抽象工廠(Abstract Factory)模式意圖:為建立一組相關或相互依賴物件提供了一個介面,而且無需指定它們的具體類。

抽象工廠可以向客戶提供一個介面,是客戶可以在不必指定產品具體型別的情況下,建立多個產品家族中的產品物件,它強調的“系列物件”的變化。

參與者

抽象工廠模式參與者:

◊ AbstractFactory:宣告一個建立抽象產品物件的操作介面

◊ ConcreteFactory:實現建立具體產品物件的操作

◊ AbstractProduct:宣告一類產品物件介面

◊ Product

°定義一個被相應具體工廠建立的產品物件

°實現AbstractProduct介面

◊ Client:使用AbstractFactory和AbstractProduct類宣告的介面

  在抽象工廠模式中,產品的建立由ConcreteFactory來完成,抽象工廠模式的ConcreteFactory不是負責一種具體Product的建立,而是負責一個Product族的建立。

分析:

抽象工廠模式將具體產品的建立延遲到具體工廠的子類中,這樣將物件的建立封裝起來,可以減少客戶端與具體產品類之間的依賴,從而使系統耦合度低,這樣更有利於後期的維護和擴充套件

其實現要點有:

提供一系列物件的介面。問:如何去實現呢?答:提供多個產品的抽象介面

建立多個產品族中的多個產品物件。問:如何做到呢?答:每個具體工廠建立一個產品族中的多個產品物件,多個具體工廠就可以建立多個產品族中的多個物件了。

適用情況

1.系統不依賴於產品類例項如何被建立,組合和表達的細節。

2.系統的產品有多於一個的產品族,而系統只消費其中某一族的產品 

3.同屬於同一個產品族是在一起使用的。這一約束必須在系統的設計中體現出來。

4.系統提供一個產品類的庫,所有產品以同樣的接口出現,從而使客戶端不依賴於實現。

特點

◊ 隔離了具體類的生成,客戶不需要知道怎樣生成每一個具體Product,什麼時間生成的。它將客戶與具體的類分離,依賴於抽象類,耦合性低。

◊ 一個產品族中的多個物件設計成一起工作,它能保證客戶端始終只使用一個產品族中的物件。這對一些需要根據當前環境來決定其行為的軟體系統來說是非常實用的一種設計模式。

◊ 有利於更換產品系列,由於客戶端只依賴於抽象類,更換產品系列時,只需要更改一下具體工廠名就可以。

◊ 難以支援新種類的產品,這是因為抽象工廠介面確定了可以被建立的產品集合,支援新種類的產品就需要擴充套件該工廠介面,這將引起抽象工廠類及其所有子類的改變。

優點:

1.它分離了具體的類

2.它使得易於交換產品系列

3.它有利於產品的一致性

缺點:

難以支援新種類的產品

抽象工廠模式與工廠方法模式區別

◊ 工廠方法模式只有一個抽象產品類,而抽象工廠模式可以有多個抽象產品類。

◊ 工廠方法模式針對一個產品等級結構,可以派生出多個具體產品類;抽象工廠模式針對面向多個產品等級結構,每個抽象產品類可以派生出多個具體產品類。

/// <summary>
    /// 下面以絕味鴨脖連鎖店為例子演示下抽象工廠模式
    /// 因為每個地方的喜歡的口味不一樣,有些地方喜歡辣點的,有些地方喜歡吃不辣點
    /// 客戶端呼叫
    /// </summary>
    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();
        }
    }

    /// <summary>
    /// 抽象工廠類,提供建立兩個不同地方的鴨架和鴨脖的介面
    /// </summary>
    public abstract class AbstractFactory
    {
        // 抽象工廠提供建立一系列產品的介面,這裡作為例子,只給出了絕味中鴨脖和鴨架的建立介面
        public abstract YaBo CreateYaBo();
        public abstract YaJia CreateYaJia();
    }

    /// <summary>
    /// 南昌絕味工廠負責製作南昌的鴨脖和鴨架
    /// </summary>
    public class NanChangFactory : AbstractFactory
    {
        // 製作南昌鴨脖
        public override YaBo CreateYaBo()
        {
            return new NanChangYaBo();
        }
        // 製作南昌鴨架
        public override YaJia CreateYaJia()
        {
            return new NanChangYaJia();
        }
    }

    /// <summary>
    /// 上海絕味工廠負責製作上海的鴨脖和鴨架
    /// </summary>
    public class ShangHaiFactory : AbstractFactory
    {
        // 製作上海鴨脖
        public override YaBo CreateYaBo()
        {
            return new ShangHaiYaBo();
        }
        // 製作上海鴨架
        public override YaJia CreateYaJia()
        {
            return new ShangHaiYaJia();
        }
    }

    /// <summary>
    /// 鴨脖抽象類,供每個地方的鴨脖類繼承
    /// </summary>
    public abstract class YaBo
    {
        /// <summary>
        /// 列印方法,用於輸出資訊
        /// </summary>
        public abstract void Print();
    }

    /// <summary>
    /// 鴨架抽象類,供每個地方的鴨架類繼承
    /// </summary>
    public abstract class YaJia
    {
        /// <summary>
        /// 列印方法,用於輸出資訊
        /// </summary>
        public abstract void Print();
    }

    /// <summary>
    /// 南昌的鴨脖類,因為江西人喜歡吃辣的,所以南昌的鴨脖稍微會比上海做的辣
    /// </summary>
    public class NanChangYaBo : YaBo
    {
        public override void Print()
        {
            Console.WriteLine("南昌的鴨脖");
        }
    }

    /// <summary>
    /// 上海的鴨脖沒有南昌的鴨脖做的辣
    /// </summary>
    public class ShangHaiYaBo : YaBo
    {
        public override void Print()
        {
            Console.WriteLine("上海的鴨脖");
        }
    }

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

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

抽象工廠的分析

抽象工廠模式很難支援新種類產品的變化。這是因為抽象工廠介面中已經確定了可以被建立的產品集合,如果需要新增新產品,此時就必須去修改抽象工廠的介面,這樣就涉及到抽象工廠類的以及所有子類的改變,這樣也就違背了“開發——封閉”原則。

.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);
    }
}

java 

工廠方法模式與抽象工廠模式對比:

工廠方法模式  抽象工廠模式

針對的是一個產品等級結構    針對的是面向多個產品等級結構
一個抽象產品類    多個抽象產品類
可以派生出多個具體產品類    每個抽象產品類可以派生出多個具體產品類
一個抽象工廠類,可以派生出多個具體工廠類    一個抽象工廠類,可以派生出多個具體工廠類
每個具體工廠類只能建立一個具體產品類的例項    每個具體工廠類可以建立多個具體產品類的例項

 

水果抽象介面:

package com.design.abstractfactory;

public interface Fruit {

    void fruitInfo();
}

 

蔬菜抽象介面:

package com.design.abstractfactory;

public interface Vegetable {

    void vegetableInfo();
}

工廠抽象介面:

package com.design.abstractfactory;

public interface Factory {

    Fruit createFruit();

    Vegetable createVegetable();
}

 

具體類:北方水果

 

package com.design.abstractfactory;

public class NorthFruit implements Fruit {
    @Override
    public void fruitInfo() {
        System.out.println("North-Apple");
    }
}

 

具體類:南方水果

package com.design.abstractfactory;

public class SouthFruit implements Fruit {
    @Override
    public void fruitInfo() {
        System.out.println("South-Banana");
    }
}

 

具體類:北方蔬菜

package com.design.abstractfactory;

public class NorthVegetable implements Vegetable {
    @Override
    public void vegetableInfo() {
        System.out.println("North-Tomato");
    }
}

 

具體類:南方蔬菜

package com.design.abstractfactory;

public class SouthVegetable implements Vegetable {
    @Override
    public void vegetableInfo() {
        System.out.println("South-Taro");
    }
}

 

具體類:北方產品工廠

package com.design.abstractfactory;

public class NorthProductFactory implements Factory {
    @Override
    public Fruit createFruit() {
        return new NorthFruit();
    }

    @Override
    public Vegetable createVegetable() {
        return new NorthVegetable();
    }
}

 

具體類:南方產品工廠

package com.design.abstractfactory;

public class SouthProductFactory implements Factory {
    @Override
    public Fruit createFruit() {
        return new SouthFruit();
    }

    @Override
    public Vegetable createVegetable() {
        return new SouthVegetable();
    }
}

 

測試類:

package com.design.abstractfactory;

public class Client {

    public static void main(String[] args){
        Factory northFactory = new NorthProductFactory();
        Factory southFactory = new SouthProductFactory();

        System.out.println("北方產品:");
        northFactory.createFruit().fruitInfo();
        northFactory.createVegetable().vegetableInfo();

        System.out.println("南方產品:");
        southFactory.createFruit().fruitInfo();
        southFactory.createVegetable().vegetableInfo();
    }

}
輸出:

 

個人總結:

建立多個的抽象產品物件,對應對個系列一個抽象工廠類,定義可建立抽象產品系列,具體工廠類實現抽象工廠類

擴充套件知識:

擴充套件知識:

 (1) 產品等級結構產品等級結構即產品的繼承結構,如一個抽象類是電視機,其子類有海爾電視機、海信電視機、TCL電視機,則抽象電視機與具體品牌的電視機之間構成了一個產品等級結構,抽象電視機是父類,而具體品牌的電視機是其子類。

 (2) 產品族:在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不同產品等級結構中的一組產品,如海爾電器工廠生產的海爾電視機、海爾電冰箱,海爾電視機位於電視機產品等級結構中,海爾電冰箱位於電冰箱產品等級結構中,海爾電視機、海爾電冰箱構成了一個產品族。

抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形式。

每一個具體工廠可以生產屬於一個產品族的所有產品,

當一個工廠等級結構可以創建出分屬於不同產品等級結構的一個產品族中的所有物件時,抽象工廠模式比工廠方法模式更為簡單、更有效率。

參考文獻:

http://www.cnblogs.com/zhili/p/AbstractFactory.html

https://www.cnblogs.com/libingql/archive/2012/12/09/2809754.html

https://blog.csdn.net/mark_lq/article/details/45132113