C#設計模式系列:工廠方法模式(Factory Method)

libingql發表於2014-01-04

1. 工廠方法模式簡介

1.1 定義

  工廠方法模式定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法模式是以一個類的例項化延遲到其子類。

  Factory Method模式用於在不指定待建立物件的具體類的情況下建立物件。

  Factory Method模式的主要意圖是隱藏物件建立的複雜性。Client通常不指定要建立的具體類,Client將面向介面或抽象類進行編碼,讓Factory類負責建立具體的型別。通常Factory類有一個返回抽象類或者介面的靜態方法。Client通常提供某種資訊讓Factory類使用提供的資訊來確定建立並返回哪個子類。

  將建立子類的責任抽象出來的好處是允許Client完全無需考慮依賴類是如何建立的,這遵守依賴倒置原則(Dependency Inversion Principle,DIP)。Factory Method模式另外一個好處是把負責物件建立的程式碼集中起來,如果需要修改物件生成方式,可以輕鬆定位並更新,而不會影響到依賴它的程式碼。

1.2 使用頻率

  

2. 工廠方法模式結構

2.1 結構圖

2.2 參與者

  工廠方法模式參與者:

  ◊ Product:Product角色,定義工廠方法所建立的物件的介面

  ◊ ConcreteProduct:具體Product角色,實現Product介面

  ◊ Factory

    ° 抽象的工廠角色,宣告工廠方法,該方法返回一個Product型別的物件

    ° Factory可以定義一個工廠方法的預設實現,返回一個預設的ConcreteProduct物件。可以呼叫工廠方法以建立一個Product物件。

  ◊ ConcreteFactory:具體的工廠角色,建立具體Product的子工廠,重寫工廠方法以返回一個ConcreteProduct例項

3. 工廠方法模式結構實現

  Product.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Structural
{
    /// <summary>
    /// 定義Product抽象類,Client呼叫Product抽象類,並由Factory來建立具體類。
    /// </summary>
    public abstract class Product
    {
    }
}

  ConcreteProductA.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Structural
{
    public class ConcreteProductA : Product
    {
    }
}

  ConcreteProductB.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Structural
{
    public class ConcreteProductB : Product
    {
    }
}

  Factory.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Structural
{
    public abstract class Factory
    {
        public abstract Product CreateProduct();
    }
}

  ConcreteFactoryA.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Structural
{
    public class ConcreteFactoryA : Factory
    {
        public override Product CreateProduct()
        {
            return new ConcreteProductA();
        }
    }
}

  ConcreteFactoryB.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Structural
{
    public class ConcreteFactoryB : Factory
    {
        public override Product CreateProduct()
        {
            return new ConcreteProductB();
        }
    }
}

  Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DesignPatterns.FactoryMethodPattern.Structural;

namespace DesignPatterns.FactoryMethodPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            Factory[] factories = new Factory[2];
            factories[0] = new ConcreteFactoryA();
            factories[1] = new ConcreteFactoryB();

            foreach (Factory factory in factories)
            {
                Product product = factory.CreateProduct();
                Console.WriteLine("Created {0}", product.GetType().Name);
            }
        }
    }
}

  執行輸出:

Created ConcreteProductA
Created ConcreteProductB
請按任意鍵繼續. . .

4. 工廠方法模式實踐應用

  假設你現在是一家KFC的管理者,要給顧客提供一系列的食品,如雞翅、雞腿等,顧客沒要求一種食品,KFC應當可以很快生產出來,採用工廠模式來實現這個過程。

  KFCFood.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Practical
{
    /// <summary>
    /// 抽象的KFC食品,Product角色
    /// </summary>
    public abstract class KFCFood
    {
        public abstract void Display();
    }
}

  Chicken.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Practical
{
    public class Chicken : KFCFood
    {
        public override void Display()
        {
            Console.WriteLine("雞腿 + 1");
        }
    }
}

  Wings.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Practical
{
    public class Wings : KFCFood
    {
        public override void Display()
        {
            Console.WriteLine("雞翅 + 1");
        }
    }
}

  IKFCFactory.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Practical
{
    public interface IKFCFactory
    {
        KFCFood CreateFood();
    }
}

  ChickenFactory.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Practical
{
    public class ChickenFactory : IKFCFactory
    {
        public KFCFood CreateFood()
        {
            return new Chicken();
        }
    }
}

  WingsFactory.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.FactoryMethodPattern.Practical
{
    public class WingsFactory : IKFCFactory
    {
        public KFCFood CreateFood()
        {
            return new Wings();
        }
    }
}

  Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DesignPatterns.FactoryMethodPattern.Practical;

namespace DesignPatterns.FactoryMethodPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            // 定義一個雞腿工廠
            IKFCFactory factory = new ChickenFactory();
            // 生產雞腿
            KFCFood food1 = factory.CreateFood();
            food1.Display();
            // 生產雞腿
            KFCFood food2 = factory.CreateFood();
            food2.Display();
            // 生產雞腿
            KFCFood food3 = factory.CreateFood();
            food3.Display();
        }
    }
}

  執行輸出:

雞腿 + 1
雞腿 + 1
雞腿 + 1
請按任意鍵繼續. . .

  在以上例子中,使用工廠模式的好處:

  1>. 客戶端在建立產品的時候只需指定一個子工廠而無需瞭解該子工廠具體建立什麼產品;

  2>. 當需求有變動,要不food1、food2、food3均改為“雞翅”的時候,只需將

IKFCFactory factory = new ChickenFactory();

  改為

IKFCFactory factory = new WingsFactory();

  即可;

  3>. 在工廠方法模式中,核心的工廠類不是負責所有產品的建立,而是將具體的建立工作交給子類ConcreteFactory去做。工廠類僅僅負責給出具體工廠必須實現的介面,而不涉及哪一個產品類被例項化這種細節。工廠方法模式可以使得系統在不需要修改原有程式碼的情況下引進新產品,如現在要增加一種新的產品“薯條”,則無需修改原有程式碼,只需增加一個“薯條”產品類和一個相應的“薯條”子工廠即可。在工廠方法模式中,子工廠與產品類往往具有平行的等級結構,它們之間一一對應。

5. 工廠方法模式應用分析

5.1 工廠方法模式適用情形

  ◊ 當一個類不知道它所必須建立的物件的類資訊的時候

  ◊ 當一個類希望由它來指定它所建立的物件的時候

  ◊ 當類將建立物件的職責委託給多個輔助子類中的某一個,並且希望將哪一個輔助之類是代理者這一資訊區域性化的時候

5.2 工廠方法模式特點

  ◊ 使用工廠方法在一個類的內部建立物件通常比直接建立物件更靈活

  ◊ 工廠方法模式通過物件導向的手法,將所要建立的具體物件的建立工作延遲到子類,從而提供了一種擴充套件的策略,較好的解決了緊耦合的關係

  ◊ 工廠方法模式遵守依賴倒置原則(Dependency Inversion Principle,DIP)

5.3 工廠方法模式與簡單工廠模式區別

  ◊ 工廠方法模式和簡單工廠模式在結構上的不同是很明顯的。工廠方法模式的核心是一個抽象工廠類,而簡單工廠模式把核心放在一個具體工廠類上。工廠方法模式可以允許很多具體工廠類從抽象工廠類中將建立行為繼承下來,從而可以成為多個簡單工廠模式的綜合,進而推廣了簡單工廠模式。

  ◊ 工廠方法模式退化後可以變得很像簡單工廠模式。如果非常確定一個系統只需要一個具體工廠類,那麼就不妨把抽象工廠類合併到具體的工廠類中去。由於只有一個具體工廠類,所以不妨將工廠方法改成為靜態方法,這時候就得到了簡單工廠模式

相關文章