- 抽象工廠模式
- 優化抽象工廠
- 異步工廠
在學習抽象工廠模式前,先來回顧一下前面的簡單工廠和工廠方法模式,簡單工廠的職責非常簡單:構造某個物體型別,然后把實體作為抽象型別回傳;
工廠方法模式則進一步抽象出一個抽象的創建者和一個抽象的產品型別,而實際的執行程序是具體工廠創建具體的產品型別,具體工廠和具體產品型別都可以被抽象為之前定義的抽象創建者和抽象產品型別,這種模式即便面對的是一個很龐大的具有復雜家族關系的型別系統,客戶程式在操作的程序中仍然可以基于抽象創建者獲得滿足某種抽象型別的產品實體,
但在很多場景下,需要創建的不是僅僅繼承自單個抽象型別的產品,它們本身就是多個具有一定依賴關系,但非同源的型別,
抽象工廠模式
抽象工廠模式可以應對這種情況,它能夠產生一系列具有相關依賴關系的型別,
Provide an interface for creating families of related or dependent objects.
— Design Patterns : Elements of Reusable Object-Oriented Software
抽象工廠可以回傳一系列相關或相互依賴物件的介面,另外抽象工廠自身也需要一個介面,這個介面定義中包括回傳那些相關物件介面的方法定義,
其UML類圖如下:

其中IProductA IProductB就是相關或相互依賴物件的介面,物體工廠會生產實作了這些介面的物體產品,IAbstractFactory是抽象工廠的介面,定義了生產IProductA、IProductB的方法,物體工廠自行決定如何實作抽象工廠介面定義的生產方法,
實作代碼:
public interface IProductA { };
public interface IProductB { };
public interface IAbstractFactory
{
IProductA CreateProductA();
IProductB CreateProductB();
}
public class ProductA1 : IProductA { }
public class ProductA2 : IProductA { }
public class ProductB1 : IProductB { }
public class ProductB2 : IProductB { }
public class ConcreteFactory1 : IAbstractFactory
{
public IProductA CreateProductA()
{
return new ProductA1();
}
public IProductB CreateProductB()
{
return new ProductB1();
}
}
public class ConcreteFactory2 : IAbstractFactory
{
public IProductA CreateProductA()
{
return new ProductA2();
}
public IProductB CreateProductB()
{
return new ProductB2();
}
}
呼叫:
[Test]
public void AbstractFactoryTest()
{
IAbstractFactory factory = new ConcreteFactory1();
IProductA productA = factory.CreateProductA();
IProductB productB = factory.CreateProductB();
Assert.AreEqual(typeof(ProductA1), productA.GetType());
Assert.AreEqual(typeof(ProductB1), productB.GetType());
}
從呼叫端代碼可以發現一個問題,同前面工廠方法模式一樣,Client與某個具體工廠耦合在一起,所以這里也可以采用依賴注入的方式“解決”這個問題,把這一步的處理推給上一層的呼叫端,
優化抽象工廠模式
這套基于經典的抽象工廠模式的代碼還有可以優化的地方:
- 首先具體工廠的代碼重復性太高,
- 另外具體工廠與具體的產品系結,如果需要改變產品組合的方式,就得要么修改具體工廠的代碼,要么創建新的工廠,改動都很大,
- 還有個更嚴重的問題,如果要添加新的抽象產品,那么從抽象工廠介面到每個具體實作都需要修改,幾乎是牽一發動全身,
針對第一點的優化方案,可以提取出一個具體工廠共用的基類AbstractFactoryBase,讓它實作抽象介面的創建方法,如果某個工廠的Create方法比較特殊,可以重寫基類的Create方法,
但是基類工廠并不知道具體工廠要創建的是怎樣的產品組合,這可以在實體化具體工廠的時候傳遞一個抽象產品與具體產品的映射(可以是字典的形式),讓基類根據映射關系來運作,或者可以基于現成的IOC容器來配置這樣的映射,這樣第二個、第三個問題也就都迎刃而解了,
實作代碼如下:
public interface IAbstractFactoryWithMapper
{
T Create<T>() where T : class;
}
public abstract class AbstractFactoryBase : IAbstractFactoryWithMapper
{
protected IDictionary<Type, Type> mapper;
public AbstractFactoryBase(IDictionary<Type, Type> mapper)
{
this.mapper = mapper;
}
public virtual T Create<T>() where T : class
{
if (mapper == null || mapper.Count == 0 || !mapper.ContainsKey(typeof(T)))
{
throw new ArgumentNullException();
}
Type targetType = mapper[typeof(T)];
return (T)Activator.CreateInstance(targetType);
}
}
public class ConcreteFactory : AbstractFactoryBase
{
public ConcreteFactory(IDictionary<Type, Type> mapper) : base(mapper) { }
}
呼叫:
[Test]
public void AbstractFactoryWithMapperTest()
{
IDictionary<Type, Type> dictionary = new Dictionary<Type, Type>();
dictionary.Add(typeof(IProductA), typeof(ProductA1));
dictionary.Add(typeof(IProductB), typeof(ProductB1));
IAbstractFactoryWithMapper factory = new ConcreteFactory(dictionary);
IProductA productA = factory.Create<IProductA>();
IProductB productB = factory.Create<IProductB>();
Assert.AreEqual(typeof(ProductA1), productA.GetType());
Assert.AreEqual(typeof(ProductB1), productB.GetType());
}
異步工廠
有些時候工廠創建產品實體的程序比較復雜,或者涉及網路、資料庫等外部資源的訪問,整體耗時較長;這種情況下,如果工廠支持異步呼叫,客戶程式就可以只向工廠發一個請求,然后接著干別的事,等收到工廠創建完成的通知后再回來接著處理,
異步工廠實作:
public interface IProduct { };
public interface IFactory
{
IProduct Create();
}
public interface IFactoryWithNotifier : IFactory
{
void Create(Action<IProduct> callBack);
}
//物體結構部分
public class ConcreteProduct : IProduct { }
public class ConcreteFactory : IFactoryWithNotifier
{
public IProduct Create() //同步構造
{
return new ConcreteProduct();
}
public void Create(Action<IProduct> callBack) //異步構造
{
IProduct product = Create();
callBack(product);
}
}
//為方便單元測驗構造的訂閱者
public class Subscriber
{
private IProduct product;
public void SetProduct(IProduct product)
{
this.product = product;
}
public IProduct GetProduct()
{
return product;
}
}
呼叫:
[Test]
public void AsyncFactoryTest()
{
IFactoryWithNotifier factoryWithNotifier = new ConcreteFactory();
Subscriber subscribe = new Subscriber();
Action<IProduct> callback = new Action<IProduct>(subscribe.SetProduct);
Assert.IsNull(subscribe.GetProduct());
factoryWithNotifier.Create(callback);
Assert.IsNotNull(subscribe.GetProduct());
}
參考書籍:
王翔著 《設計模式——基于C#的工程化實作及擴展》
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/4542.html
標籤:設計模式
上一篇:策略模式
下一篇:設計模式之策略模式
