1. 程式人生 > >設計模式(3)抽象工廠模式(Abstract Factory)

設計模式(3)抽象工廠模式(Abstract Factory)

開始 line andro 依賴 red 單例 clas 面向接口 抽象工廠方法

設計模式(0)簡單工廠模式

設計模式(1)單例模式(Singleton)

設計模式(2)工廠方法模式(Factory Method)

源碼地址

0 抽象工廠模式簡介

0.0 抽象工廠模式定義

抽象工廠模式一般的書面定義為:提供一個創建一系列相關或相互依賴對象的接口,而無需指定他們具體的類

提供創建接口,無需指定具體實現類,這個原則在簡單工廠模式和工廠方法模式篇已經反復講到了,這是面向接口編程的一個基本準則,很顯然,從抽象工廠模式的一般定義中可以看出這也是抽象工廠模式的一個核心,而抽象工廠模式的另一個核心是要解決一系列相關或相依賴對象(產品族)創建的問題。這也是這幾種工廠模式的細節區別所在的關鍵點所在,初學設計模式時往往因為沒有認識到這一點區別而對幾種工廠模式難以理解

我們可以簡單的這麽理解,抽象工廠模式不單單要解決對象的創建問題,還要涉及到創建的對象之間的相互依賴或者約束關系。工廠方法模式和簡單工廠模式解決了單個產品對象創建的問題,它們只關心單個產品對象的創建,而抽象工廠模式是關註的產品族(多個相互關聯對象)的創建,最終創建的產品族形成一個新的產品對象。

抽象工廠模式的結構圖如下:

技術分享

AbstractFactory:抽象工廠類,定義創建某個產品所需相關對象的操作接口

ProductFactory1/ProductFactory2:具體的工廠類,實現抽象工廠定義的方法,負責某個產品所需所有對象創建操作接口的具體實現。

AbstractProductA/AbstractProductB:定義某一類產品對象的接口

ProductA1/ProductA2/ProductB1/ProductB2:具體產品對象的實現

0.1 抽象工廠模式應用場景

如果對上面的文字描述還不能有一個直觀的認識,我們仍然從一個簡單的應用場景來說明抽象工廠模式的引入時機。

野外商店老板為了更好的服務眾英雄,特將店內隱身藥水進行了一次升級,分為紅瓶裝(瓶口直徑2cm)、藍瓶裝(瓶口直徑5cm)2款,並且2種瓶子分別搭配圓形(2cm)和方形(5cm)兩種款式的瓶蓋。英雄們來到商店後,只需要將自己的的需要告訴商店老板,老板根據英雄的要求,去取瓶子和蓋子進行組裝即可。

在應用抽象工廠模式之前,我們很簡單的使用簡單工廠模式實現這個需求。

定義瓶子接口及實現類

/// <summary>
/// 定義瓶子接口
/// </summary>
public interface IBottle
{
    /// <summary>
    /// 展示自己的信息
    /// </summary>
    void ShowInfo();
}
/// <summary>
/// 紅色瓶子
/// </summary>
public class RedBottle : IBottle
{
    /// <summary>
    /// 展示自己的信息
    /// </summary>
    public void ShowInfo()
    {
        Console.WriteLine("我是一個熱情火辣的紅色瓶子,我的瓶口直徑是2cm。");
    }
}

定義瓶蓋接口及實現類

/// <summary>
/// 定義瓶蓋接口
/// </summary>
public interface ICap
{
    /// <summary>
    /// 展示自己的信息
    /// </summary>
    void ShowInfo();
}
/// <summary>
/// 圓形瓶蓋
/// </summary>
public class RoundCap : ICap
{
    /// <summary>
    /// 展示自己的信息
    /// </summary>
    public void ShowInfo()
    {
        Console.WriteLine("我是一個圓形瓶蓋,我的直徑是2cm。");
    }
}
/// <summary>
/// 方形瓶子
/// </summary>
public class SquareCap : ICap
{
    /// <summary>
    /// 展示自己的信息
    /// </summary>
    public void ShowInfo()
    {
        Console.WriteLine("我是一個方形瓶蓋,我的直徑是5cm。");
    }
}

定義創建瓶子和瓶蓋的簡單工廠

/// <summary>
/// 瓶子創建工廠方法
/// </summary>
public class BottleFactory
{
    /// <summary>
    /// 創建瓶子對象
    /// </summary>
    /// <param name="color">瓶子顏色</param>
    /// <returns></returns>
    public static IBottle CreateBottle(string color)
    {
        if (color == "red")
            return new RedBottle();
        if (color == "blue")
            return new BlueBottle();
        return null;
    }
}
/// <summary>
/// 瓶蓋創建工廠方法
/// </summary>
public class CapFactory
{
    /// <summary>
    /// 創建瓶子對象
    /// </summary>
    /// <param name="shape">瓶蓋形狀</param>
    /// <returns></returns>
    public static ICap CreateCap(string shape)
    {
        if (shape == "round")
            return new RoundCap();
        if (shape == "square")
            return new SquareCap();
        return null;
    }
}

最終成品組裝類定義

/// <summary>
/// 隱形藥水組裝者
/// </summary>
public class ProductMaker
{
    private IBottle _bottle; // 瓶子對象
    private ICap _cap; // 瓶蓋對象

    /// <summary>
    /// 創建最終藥水對象
    /// </summary>
    /// <param name="bottleColor"></param>
    /// <param name="capShape"></param>
    public void MakeProduct(string bottleColor, string capShape)
    {
        _bottle = BottleFactory.CreateBottle(bottleColor);
        _cap = CapFactory.CreateCap(capShape);
        Console.WriteLine("準備英雄需要的瓶子和瓶蓋。");
        _bottle.ShowInfo();
        _cap.ShowInfo();
        Console.WriteLine("開始往瓶子了灌入隱形藥水,然後封上瓶蓋。");
    }
}

客戶端調用

static void Main(string[] args)
{
    ProductMaker pm = new ProductMaker();
    pm.MakeProduct("red", "round"); // 提供給英雄紅瓶子圓蓋子的隱形藥水
    Console.WriteLine();
    pm.MakeProduct("blue", "square"); // 提供給英雄藍瓶子方蓋子的隱形藥水
    Console.ReadLine();
}

這樣,我們通過接口進行隔離,解決了不同瓶子,不同蓋子創建時,客戶端無需關心具體創建過程,只需要告訴工廠需要何種類型的對象即可。但同時會暴露一個很明顯的問題就是,我們創建的瓶子和瓶蓋2個對象並不是孤立存在的,2個對象之間是有明顯的相互關系的,那就是平口尺寸必須和瓶蓋尺寸保持一直,否則就會讓店老板出現灌裝好藥水卻擰不上蓋子的尷尬。此時應該會對上面提到的抽象工廠的定義有進一步的理解,也在這種場景下,是我們必須要引入抽象工廠模式的時候了。

1 抽象工廠模式詳解

0、提煉抽象工廠類

根據抽象工廠方法的結構圖,我們首先定義個一個抽象工廠類,該抽象工廠定義瓶子和瓶蓋2個對象的創建接口。

/// <summary>
/// 抽象工廠類
/// </summary>
public abstract class AbstractFactory
{
    /// <summary>
    /// 創建瓶子
    /// </summary>
    /// <returns></returns>
    public abstract IBottle CreateBottle();

    /// <summary>
    /// 創建瓶蓋
    /// </summary>
    /// <returns></returns>
    public abstract ICap CreateCap();
}

1、抽象工廠的具體實現

分析產品的組合情況,實際上只存在2種類型的最終產品,紅瓶子圓蓋子和藍瓶子方蓋子,我們分別定義2個抽象工廠的具體實現類

/// <summary>
/// 紅瓶子圓蓋子工廠類
/// </summary>
public class RedBottleAndRoundCapFactory : AbstractFactory
{
    /// <summary>
    /// 創建瓶子
    /// </summary>
    /// <returns></returns>
    public override IBottle CreateBottle()
    {
        return BottleFactory.CreateBottle("red");
    }

    /// <summary>
    /// 創建瓶蓋
    /// </summary>
    /// <returns></returns>
    public override ICap CreateCap()
    {
        return CapFactory.CreateCap("round");
    }
}
/// <summary>
/// 藍瓶子方蓋子工廠類
/// </summary>
public class BlueBottleAndSquareCapFactory : AbstractFactory
{
    /// <summary>
    /// 創建瓶子
    /// </summary>
    /// <returns></returns>
    public override IBottle CreateBottle()
    {
        return BottleFactory.CreateBottle("blue");
    }

    /// <summary>
    /// 創建瓶蓋
    /// </summary>
    /// <returns></returns>
    public override ICap CreateCap()
    {
        return CapFactory.CreateCap("square");
    }
}

2、最終產品組裝類的修改實現

跟原來的實現相比較,最終產品組裝類不在從客戶端傳入瓶子、瓶蓋的參數通過對應的工廠方法創建,而是直接傳入已經定義好的瓶子瓶蓋組裝工廠類對象,能夠做到瓶子瓶蓋必須配套創建。

/// <summary>
/// 創建最終藥水對象
/// </summary>
/// <param name="factory">抽象工廠具體對象</param>
public void MakeProduct(AbstractFactory factory)
{
    _bottle = factory.CreateBottle();
    _cap = factory.CreateCap();
    Console.WriteLine("準備英雄需要的瓶子和瓶蓋。");
    _bottle.ShowInfo();
    _cap.ShowInfo();
    Console.WriteLine("開始往瓶子了灌入隱形藥水,然後封上瓶蓋。");
}

3、客戶端調用

ProductMaker pm = new ProductMaker();
AbstractFactory factory = new RedBottleAndRoundCapFactory(); // 提供給英雄紅瓶子圓蓋子的隱形藥水
pm.MakeProduct(factory);
Console.WriteLine();
factory = new BlueBottleAndSquareCapFactory(); // 提供給英雄藍瓶子方蓋子的隱形藥水
pm.MakeProduct(factory);
Console.ReadLine();

2 總結

通過創建的多個對象之間的關聯關系闡述了抽象工廠模式與其他工廠模式的區別以及使用時機。基於上面的示例,我們可以總結出抽象工廠模式的具有以下優點:

0、分離接口和實現

客戶端使用抽象工廠方法來創建需要的對象,只需要傳入抽象方法的,無需關註內部具體實現邏輯,實現接口與具體實現的分離解耦。

1、易於產品族切換

一個具體抽象工廠的實現其實就是代表一個產品族,客戶端通過參數選用不同的工廠實現,就可以在不同的產品創建中進行切換。

抽象工廠模式的缺點也顯而易見,那就是擴展新產品的過程會比較麻煩,比如一個產品族中包含的產品發生了變化,比如增加或減少部件,就需要修改抽象工廠,同時需要修改所有的抽象工廠實現類。

設計模式(3)抽象工廠模式(Abstract Factory)