- 創(chuàng)建型模式
- 簡單工廠模式
- 工廠方法模式
- IOC與工廠方法模式的結(jié)合
- 泛型工廠
- 委托工廠
創(chuàng)建型模式
創(chuàng)建型模式可以隔離客戶程序?qū)π枰獙?shí)例化類型的依賴關(guān)系,這類模式一般通過將實(shí)例化具體對象的職責(zé)委托給第三方對象的方式,使得客戶程序或者外部系統(tǒng)在獲得所需的具體類型實(shí)例的同時(shí),而不必對其發(fā)生直接的引用。
創(chuàng)建型模式包括:
- 工廠方法模式
- 單例模式
- 抽象工廠模式
- 創(chuàng)建者模式
- 原型模式
按照大多數(shù)設(shè)計(jì)模式書籍采用的順序,首先從工廠方法模式開始。
簡單工廠模式
簡單工廠模式并沒有被歸入23種設(shè)計(jì)模式之列,但可以作為學(xué)習(xí)工廠方法模式前的預(yù)備。簡單工廠模式在管理對象創(chuàng)建方面,提供的是最簡單的方案,它僅僅簡單的對不同類對象的創(chuàng)建進(jìn)行了一層薄薄的封裝,客戶程序在使用時(shí),通過向簡單工廠傳遞一個(gè)類型來指定要?jiǎng)?chuàng)建的對象,其UML類圖如下:

Client需要的是具體的產(chǎn)品ConcreteProductA或者ConcreteProductB,如果直接new()就會依賴對象實(shí)例,引入簡單工廠后,Client變成了依賴IProduct和SampleFactory。
代碼示例:
//產(chǎn)品接口
public interface IProduct { };
//具體產(chǎn)品
public class ConcreteProductA : IProduct { }
public class ConcreteProductB : IProduct { }
public enum Category { A, B }
//簡單工廠
public class SampleFactory
{
public IProduct Create(Category category)
{
switch (category)
{
case Category.A:
return new ConcreteProductA();
case Category.B:
return new ConcreteProductB();
default:
throw new ArgumentOutOfRangeException();
}
}
}
調(diào)用:
[Test]
public void SampleFactoryTest()
{
SampleFactory sampleFactory = new SampleFactory();
IProduct product = sampleFactory.Create(Category.A);
Assert.AreEqual(product.GetType(), typeof(ConcreteProductA));
}
工廠方法模式
簡單工廠模式中的工廠負(fù)責(zé)生產(chǎn)所有的產(chǎn)品類型,但如果工廠負(fù)責(zé)生產(chǎn)的產(chǎn)品只有一種,就可以進(jìn)一步抽象了,這便出現(xiàn)了工廠模式。
GOF對工廠方法模式的描述是:
Define an interface for creating an object, but let subclasses decide which class toinstantiate. Factory Method lets a class defer instantiation to subclasses..
— Design Patterns : Elements of Reusable Object-Oriented Software
工廠方法模式定義了一個(gè)抽象的工廠,它的子類實(shí)體工廠都有統(tǒng)一通用的工廠方法,用來生產(chǎn)具體的產(chǎn)品,這樣就把類的實(shí)例化延遲到其子類。
工廠方法主要有四個(gè)角色:
- 抽象產(chǎn)品類型(Product),工廠要加工的對象所具有的抽象特征實(shí)體。
- 具體產(chǎn)品類型(Concrete Product),實(shí)現(xiàn)客戶程序所需要的抽象特質(zhì)的類型,它就是工廠需要延遲實(shí)例的備選對象。
- 抽象工廠類型(IFactory),定義一個(gè)工廠方法的默認(rèn)實(shí)現(xiàn),它返回抽象產(chǎn)品類型。
- 具體工廠類型(Concrete Factory):重新定義了產(chǎn)品創(chuàng)建過程,返回具體產(chǎn)品類型。
UML類圖

代碼示例:
//抽象產(chǎn)品類型
public interface IProduct
{
string Name { get; } //抽象產(chǎn)品所必須具有的特征
}
//具體產(chǎn)品類型
public class ProductA : IProduct
{
public string Name { get { return "A"; } }
}
public class ProductB : IProduct
{
public string Name { get { return "B"; } }
}
//抽象工廠類型
public interface IFactory
{
IProduct Create(); //抽象的工廠描述
}
//具體工廠類型
public class FactoryA : IFactory
{
public IProduct Create()
{
return new ProductA();
}
}
public class FactoryB : IFactory
{
public IProduct Create()
{
return new ProductB();
}
}
調(diào)用:
public class Client1
{
public void SomeMethod()
{
IFactory factory = new FactoryA();
IProduct product = factory.Create();
}
}
客戶程序需要使用IProduct的時(shí)候,只需要獲取到IFactory,通過調(diào)用其統(tǒng)一制定的Create()方法就可以獲取到具體的產(chǎn)品,具體需要哪個(gè)產(chǎn)品由Factory決定。這樣就隔離了客戶程序?qū)唧w產(chǎn)品的依賴,但這里還有個(gè)問題是在獲取IFactory的時(shí)候需要初始化具體的工廠,這樣就對具體的工廠產(chǎn)生了依賴。
IOC與工廠方法模式的結(jié)合
為了解決上述問題,可以把IFactory作為客戶程序的參數(shù),然后采用依賴注入的方式將具體的工廠注入:
public class Client2
{
private IFactory factory;
public Client2(IFactory factory)
{
this.factory = factory;
}
public string SomeMethod()
{
IProduct product = factory.Create();
return product.Name;
}
}
這樣客戶程序就變成了真正地只依賴IFactory和IProduct了,但問題是不論采用哪種依賴注入框架,都需要注冊接口與實(shí)例的映射關(guān)系,那么這種方式就只是相當(dāng)于把對具體產(chǎn)品的依賴“甩”到了“客戶程序的客戶程序”,怎么辦呢,退無可退的時(shí)候,考慮把接口與實(shí)例的映射關(guān)系放到配置文件吧。
泛型工廠
上面的工廠方法模式中,每個(gè)具體的工廠負(fù)責(zé)生產(chǎn)一種產(chǎn)品,且都實(shí)現(xiàn)了抽象工廠的Create()方法,于是借助泛型可以實(shí)現(xiàn)進(jìn)一步的抽象:
public interface IFactory<T>
{
T Create(); //抽象的工廠描述
}
public abstract class FactoryBase<T> : IFactory<T> where T : new()
{
public virtual T Create()
{
return new T();
}
}
public class ProductAFactory : FactoryBase<ProductA> {
public override ProductA Create(){
return new ProductA();
}
}
public class ProductBFactory : FactoryBase<ProductB> { }
在抽象工廠和具體的工廠之間增加了支持泛型的FactoryBase,在這里實(shí)現(xiàn)了通用的Create()方法。如果某個(gè)具體工廠需要特殊的Create流程,只需重寫虛方法即可。這樣在工廠種類比較多而流程有大多相同的情況下,可以減少很多代碼。
委托工廠
前面代碼中的工廠生產(chǎn)的產(chǎn)品都是對象,如果需要生產(chǎn)的是方法呢,C#的委托機(jī)制可以方便地滿足這種需求。
委托的本質(zhì)是方法的指針,是對一類方法的抽象。所以委托本身就可以作為抽象產(chǎn)品的定義,而與委托簽名一致的方法就是具體產(chǎn)品了。
代碼示例:
public delegate int CalculateHandler(params int[] items);
public class Calculator
{
public int Add(params int[] items)
{
int result = 0;
foreach (var item in items)
{
result += item;
}
return result;
}
public int Multi(params int[] items)
{
int result = 1;
foreach (var item in items)
{
result *= item;
}
return result;
}
}
public class AddHandlerFactory : IFactory<CalculateHandler>
{
public CalculateHandler Create()
{
return new Calculator().Add;
}
}
public class MultiHandlerFactory : IFactory<CalculateHandler>
{
public CalculateHandler Create()
{
return new Calculator().Multi;
}
}
調(diào)用:
[Test]
public void CalculateHandlerTest()
{
CalculateHandler addHandler = new AddHandlerFactory().Create();
Assert.AreEqual(1 + 2 + 3, addHandler(1, 2, 3));
CalculateHandler multiHandler = new MultiHandlerFactory().Create();
Assert.AreEqual(1 * 2 * 3, multiHandler(1, 2, 3));
}
參考書籍:
王翔著 《設(shè)計(jì)模式——基于C#的工程化實(shí)現(xiàn)及擴(kuò)展》
|