1. 程式人生 > >設計模式的征途—4.抽象工廠(Abstract Factory)模式

設計模式的征途—4.抽象工廠(Abstract Factory)模式

上一篇的工廠方法模式引入了工廠等級結構,解決了在原來簡單工廠模式中工廠類職責太重的原則,但是由於工廠方法模式的每個工廠只生產一類產品,可能會導致系統中存在大量的工廠類,從而增加系統開銷。那麼,我們應該怎麼來重構?似乎,我們可以考慮將一些相關的產品組成一個“產品族”,由同一個工廠來統一生產,這就是本次將要學習的抽象工廠模式的基本思想。

抽象工廠模式(Abstract Factory) 學習難度:★★★★☆ 使用頻率:★★★★★

一、介面面板庫的初始設計

  M公司IT開發部接到一個開發任務,想要對以前的一個系統開發一套介面面板庫,可以對該桌面系統軟體進行介面美化。這樣,使用者就可以在使用時通過選單來選擇面板,不同的面板將提供視覺效果不同的按鈕、文字框以及組合框等介面元素,其結構示意圖如下所示:

  該面板庫需要具備良好的靈活性和可擴充套件性,使用者可以自由選擇不同的面板,開發人員也可以在不修改既有程式碼的基礎上增加新的面板。

  M公司的開發人員針對上述需求,決定現學現賣,在上次使用了工廠方法模式之後對工廠方法模式大為讚賞,決定使用工廠方法模式來進行系統的設計,為了保證系統的靈活性和可擴充套件性,提供一系列具體工廠來建立按鈕、文字框以及組合框等介面元素,客戶端針對抽象工廠來程式設計,初始結構如下圖所示:

  從上圖可以看出,此方案提供了大量的工廠來建立具體的介面元件,可以通過配置檔案來更換具體介面元件從而改變介面的風格,但是,此方案存在以下問題:

  (1)需要增加新的面板時,雖然不需要更改現有程式碼,但是需要增加大量的類,針對每一個新增具體元件都要增加一個具體工廠,類的個數會成對增加。這無疑會導致系統越來越龐大,從而增加了系統的維護成本和執行開銷

  (2)由於同一種風格的不同介面元件通常需要一起顯示,因此需要為每個元件都選擇一個具體工廠,使用者在使用時必須逐個進行設定,如果某個具體工廠選擇失誤將會導致介面顯示混亂,雖然可以適當增加一些約束語句,但是客戶端程式碼和配置檔案都較為複雜。

  綜上所述,如何減少系統中類的個數並保證客戶端每次始終就只使用一種風格的具體介面元件?這是縈繞在M公司開發人員心頭的兩個問題。

二、抽象工廠模式介紹

2.1 理清產品等級與產品族

  (1)產品等級

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

  (2)產品族

  產品族是指由同一個工廠生產的,位於不同產品等級結構中的一組,例如海爾電器廠生產的海爾電視機、海爾電冰箱,海爾電視機位於電視機產品等級結構中,而海爾電冰箱則位於電冰箱產品等級結構中,他們倆構成了一個產品族。

  產品等級與產品族的示意圖如下圖所示:

  可以看出,當系統所提供的工廠生產的具體產品並不是一個簡單的物件,而是多個位於不同產品等級結構、屬於不同型別的具體產品時,就可以使用抽象工廠模式。抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形式。

Note :抽象工廠與工廠方法最大的區別就在於,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式需要面對多個產品等級結構,一個工廠等級結構可以負責多個不同產品等級中的產品物件的建立。

2.2 抽象工廠模式概述

  抽象工廠模式為建立一組物件提供了一種方案,與工廠方法模式相比,抽象工廠模式中的具體工廠不只是建立一種產品,它負責建立一族產品。其定義如下:

Definition :抽象工廠模式提供一個建立一系列相關或相互依賴物件的介面,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,它是一種物件建立型模式。

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

  (1)Abstract Factory (抽象工廠角色):聲明瞭一組用於建立一族產品的方法,每一個方法對應一種產品。

  (2)Concrete Factory (具體工廠角色):實現了在抽象工廠中宣告的建立產品的方法,生成一組具體產品,這些產品構成了一個產品族。

  (3)Abstract Product (抽象產品角色):為每種產品宣告介面,在抽象產品中聲明瞭所有的業務方法。

  (4)Concrete Product (具體產品角色):定義具體工廠生產的具體產品物件,實現在抽象產品介面中宣告的業務方法。

三、介面面板庫的重構設計

3.1 抽象工廠模式設計方案

  M公司使用抽象工廠模式來重構了介面面板庫的設計,其基本結構如下圖所示:

3.2 重構程式碼

  (1)Abstract Product

    public interface IButton
    {
        void Display();
    }

    public interface ITextField
    {
        void Display();
    }

    public interface IComboBox
    {
        void Display();
    }

  (2)Concrete Product

  ① Spring風格Button

    public class SpringButton : IButton
    {
        public void Display()
        {
            Console.WriteLine("顯示淺綠色按鈕...");
        }
    }

    public class SpringTextField : ITextField
    {
        public void Display()
        {
            Console.WriteLine("顯示綠色邊框文字框...");
        }
    }

    public class SpringComboBox : IComboBox
    {
        public void Display()
        {
            Console.WriteLine("顯示綠色邊框下拉框...");
        }
    }

  ② Summer風格Button

    public class SummerButton : IButton
    {
        public void Display()
        {
            Console.WriteLine("顯示淺藍色按鈕...");
        }
    }

    public class SummerTextField : ITextField
    {
        public void Display()
        {
            Console.WriteLine("顯示藍色邊框文字框...");
        }
    }

    public class SummerComboBox : IComboBox
    {
        public void Display()
        {
            Console.WriteLine("顯示藍色邊框下拉框...");
        }
    }

  (3)Abstract Factory

    public interface ISkinFactory
    {
        IButton CreateButton();
        ITextField CreateTextField();
        IComboBox CreateComboBox();
    }

  (4)Concrete Factory

  ① Spring面板工廠

    // Spring面板工廠
    public class SpringSkinFactory : ISkinFactory
    {
        public IButton CreateButton()
        {
            return new SpringButton();
        }

        public IComboBox CreateComboBox()
        {
            return new SpringComboBox();
        }

        public ITextField CreateTextField()
        {
            return new SpringTextField();
        }
    }

  ② Summer面板工廠

    public class SummerSkinFactory : ISkinFactory
    {
        public IButton CreateButton()
        {
            return new SummerButton();
        }

        public IComboBox CreateComboBox()
        {
            return new SummerComboBox();
        }

        public ITextField CreateTextField()
        {
            return new SummerTextField();
        }
    }

3.3 測試結果

  (1)客戶端程式碼

    public class Program
    {
        public static void Main(string[] args)
        {
            ISkinFactory skinFactory = (ISkinFactory) AppConfigHelper.GetSkinFactoryInstance();
            if (skinFactory == null)
            {
                Console.WriteLine("讀取當前選中面板型別失敗...");
            }

            IButton button = skinFactory.CreateButton();
            ITextField textField = skinFactory.CreateTextField();
            IComboBox comboBox = skinFactory.CreateComboBox();

            button.Display();
            textField.Display();
            comboBox.Display();

            Console.ReadKey();
        }
    }

  其中,AppConfigHelper用於從以下的配置檔案中讀取SkinFactory的值去反射生成具體工廠例項,這裡配置的當前選中面板是Spring風格。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!-- 當前選中面板型別 -->
    <add key="SkinFactory" value="Manulife.ChengDu.DesignPattern.AbstractFactory.SpringSkinFactory, Manulife.ChengDu.DesignPattern.AbstractFactory"/>
  </appSettings>
</configuration>

  AppConfigHelper的具體程式碼如下:

    public class AppConfigHelper
    {
        public static string GetSkinFactoryName()
        {
            string factoryName = null;
            try
            {
                factoryName = System.Configuration.ConfigurationManager.AppSettings["SkinFactory"];
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return factoryName;
        }

        public static object GetSkinFactoryInstance()
        {
            string assemblyName = AppConfigHelper.GetSkinFactoryName();
            Type type = Type.GetType(assemblyName);

            var instance = Activator.CreateInstance(type);
            return instance;
        }
    }
View Code

  (2)除錯結果

  終於到了興奮的時刻啦,執行結果如下:

  

  這時,我們將配置檔案中的值改為SummerSkinFactory試試:

<add key="SkinFactory" value="Manulife.ChengDu.DesignPattern.AbstractFactory.SummerSkinFactory, Manulife.ChengDu.DesignPattern.AbstractFactory"/>

  再次執行程式,結果是我們想要的:

  

四、抽象工廠模式總結

4.1 抽象工廠模式主要優點

  (1)隔離了具體類的生成,使得客戶並不需要知道什麼被建立。因為這種隔離,因此更換一個具體工廠就變得相對容易。

  (2)當一個產品族中的多個物件被設計稱一起工作時,它能夠保證客戶端始終只使用同一個產品族中的物件。

  (3)增加新的產品族很方便,無需修改已有系統,符合開閉原則。

4.2 抽象工廠模式主要缺點

  增加新的產品等級結構很麻煩增加新的產品等級結構很麻煩,增加新的產品等級結構很麻煩!!!(重要的事情說三遍)因為需要對原有系統進行較大的修改,甚至需要修改抽象層程式碼,這必然會帶來較大的不便,在這個角度,它違背了開閉(對擴充套件開放,對修改封閉)原則。

  想想,如果我們需要為單選按鈕(RadioButton)提供不同面板的風格化顯示,會發現無論選擇哪種面板,單選按鈕都顯得“格格不入”。

4.3 抽象工廠模式應用場景

  (1)使用者無須關心物件的建立過程,需要將物件的建立和使用解耦 -> 這是所有工廠模式的使用前提

  (2)系統中有多餘一個的產品族,而每次都只使用其中的某一種產品族。 -> 可以通過配置檔案等方式來使得使用者可以動態地改變產品族,也可以很方便地增加新的產品族

  (3)產品等級結構穩定!設計完成之後,不會向系統中增加新的產品等級結構或刪除已有產品等級結構。 -> 並不太符合開閉原則

參考資料

      DesignPattern

  劉偉,《設計模式的藝術—軟體開發人員內功修煉之道》

作者:周旭龍

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。

相關推薦

設計模式征途4.抽象工廠Abstract Factory模式

上一篇的工廠方法模式引入了工廠等級結構,解決了在原來簡單工廠模式中工廠類職責太重的原則,但是由於工廠方法模式的每個工廠只生產一類產品,可能會導致系統中存在大量的工廠類,從而增加系統開銷。那麼,我們應該怎麼來重構?似乎,我們可以考慮將一些相關的產品組成一個“產品族”,由同一個工廠來統一生產,這就是本次將要學習的

抽象工廠Abstract Factory模式——Java設計模式

抽象工廠模式簡介 抽象工廠模式(Abstract Factory Pattern):圍繞一個超級工廠建立其他工廠。該超級工廠又稱為其他工廠的工廠。 分類:建立型模式。 在抽象工廠模式中,介面是負責

設計模式2——建立型——工廠相關:簡單工廠Simple factory工廠方法Factory method抽象工廠Abstract factory

概要 這裡試圖描述23個設計模式中的兩個工廠(Factory)相關的設計模式:工廠方法(Factorymethod),抽象工廠(Abstract factory)。 注意點: 這兩個都屬於建立型設計模式。 由於這兩個設計模式都

我的設計模式-抽象工廠Abstract Factory

抽象工廠主要是在工廠模式的基礎上,將物件例項生成工廠進行了抽象,增加了物件例項生成工廠的拓展性。 工廠模式可以參看: 以下舉例說明抽象工廠模式: 可能有多種印表機,但都有列印方法; 將原有工廠模式的印表機工廠類進行封裝,通過實現統一的介面來實現不同的印表機例項的

設計模式征途—2.簡單工廠Simple Factory模式

  工廠模式是最常用的一種建立型模式,通常所說的工廠模式一般是指工廠方法模式。本篇是是工廠方法模式的“小弟”,我們可以將其理解為工廠方法模式的預備知識,它不屬於GoF 23種設計模式,但在軟體開發中卻也應用地比較頻繁。此外,工廠方法模式還有一位“大哥”—抽象工廠模式,會在後面進行介紹。 簡單工廠

抽象工廠Abstract Factory

工廠 cnblogs null pro pes reg 抽象 blog log 抽象工廠模式是工廠模式的升級版,用於創建一組相關或者相互依賴的對象 // 抽象工廠模式 function Car (name, color) { this.name = name;

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

開始 line andro 依賴 red 單例 clas 面向接口 抽象工廠方法 設計模式(0)簡單工廠模式 設計模式(1)單例模式(Singleton) 設計模式(2)工廠方法模式(Factory Method) 源碼地址 0 抽象工廠模式簡介 0.0 抽象工廠模式定義

【Unity與23種設計模式抽象工廠模式Abstract Factory

根據 strac 結果 產品 不同 面試 public str 構建 GoF中定義: “提供一個能夠建立整個類群組或有關聯的對象,而不必指明它們的具體類。” 意思就是 根據不同的執行環境產生不同的抽象類子類 抽象工廠模式經常在面試中會涉及到 下面的例子為工廠1和

c#設計模式3抽象工廠模式Abstract Factory

bubuko write col 實現 trac 技術分享 返回 lin 子類 #region 坦克系列 abstract class Tank { abstract public void Go(); } /// &

設計模式---對象創建模式抽象工廠模式Abstract Factory

變化 實現 clas span 有關 數據庫 數據庫連接 不同的 面向 一:概念 抽象工廠模式是所有形態的工廠模式中最為抽象和最具一般性的。抽象工廠模式可以向客戶端提供一個接口,使得客戶端在不必指定產品的具體類型的情況下,能夠創建多個產品族的產品對象 二:動機

設計模式學習之抽象工廠模式Abstract Factory

轉自:https://blog.csdn.net/u012909091/article/details/38349211 要想正確理解設計模式,首先必須明確它是為了解決什麼問題而提出來的。 ——Shulin 抽象工廠設計模式概念:   &n

設計模式3——抽象工廠模式abstract-factory

  一、抽象工廠模式說明 layout title folder permalink categories tags pattern Abstract F

設計模式--抽象工廠個人筆記

一、抽象工廠的應用場景以及優缺點 1  應用場景:       如果系統需要多套的程式碼解決方案,並且每套的程式碼解決方案中又有很多相互關聯的產品型別,並且在系統中我們可以相互替換的使用一套產品的時候可以使用該模式,客戶端不需要依賴具體的實現。 2 優點

抽象工廠模式Abstract Factory

1.1.1. 目的在不指定具體類的情況下建立一系列相關或依賴物件。 通常建立的類都實現相同的介面。 抽象工廠的客戶並不關心這些物件是如何建立的,它只是知道它們是如何一起執行的。1.1.2. UML 圖1.1.3. 程式碼你可以在 GitHub 上找到這個程式碼。Abstrac

3.抽象工廠模式Abstract Factory

一、簡介 定義: 為建立一組相關或相互依賴的物件提供一個介面,而且無需指定他們的具體類。 為了方便引進抽象工廠模式,引進一個新概念:產品族(Product Family) 。所謂產品族,是指位於不同產品等級結構,功能相關聯的產品組成的家族。如圖: 圖中一共有四個產品族

設計模式征途—17.模板方法Template Method模式

opened res ati 相同 rom 配置 version factor creat 在現實生活中,很多事情都需要經過幾個步驟才能完成,例如請客吃飯,無論吃什麽,一般都包含:點單、吃東西、買單等幾個步驟,通常情況下這幾個步驟的次序是:點單=>吃東西=>買單

簡單工廠模式Abstract Factory

        一直想認認真真的學習一下設計模式,發現不開始行動起來一直找不到時間好好學習一下,索性通過部落格的方式督促自己過一遍設計模式 所謂簡單工廠模式,英文描述為Provides one level of interface higher than the facto

抽象abstract class和接口interface有什麽異同?

否則 繼承 默認 strong 什麽 成員 -s 實例 abstract 相同點: 1.抽象類和接口都不能被實例化,但可以定義抽象類和接口類型的引用。 2.一個類如果繼承了抽象類和接口,必須要對其中的抽象方法全部實現。(接口中方法默認的是public abstract修飾的

抽象abstract class和介面interface有什麼異同?

抽象類和介面都不能夠例項化,但可以定義抽象類和介面型別的引用。一個類如果繼承了某個抽象類或者實現了某個介面都需要對其中的抽象方法全部進行實現,否則該類仍然需要被宣告為抽象類。介面比抽象類更加抽象,因為抽象類中可以定義構造器,可以有抽象方法和具體方法,而介面中不能定義構造器而且其中的方法全部都是抽象方

java基礎抽象abstract class和介面Interface

抽象類(abstract class)和介面(Interface)是Java語言中對於抽象類定義進行支援的兩種機制,賦予了Java強大的面向物件能力。 二者具有很大的相似性,甚至可以相互替換,因此很多開發者在進行抽象類定義時對於abstractclass和Interface的選擇顯得比較