在學習抽象工廠模式前,先來回顧一下前面的簡單工廠和工廠方法模式。簡單工廠的職責很是簡單:構造某個實體類型,而後把實例做爲抽象類型返回;
工廠方法模式則進一步抽象出一個抽象的建立者和一個抽象的產品類型,而實際的執行過程是具體工廠建立具體的產品類型,具體工廠和具體產品類型均可以被抽象爲以前定義的抽象建立者和抽象產品類型,這種模式即使面對的是一個很龐大的具備複雜家族關係的類型系統,客戶程序在操做的過程當中仍然能夠基於抽象建立者得到知足某種抽象類型的產品實例。數據庫
但在不少場景下,須要建立的不是僅僅繼承自單個抽象類型的產品,它們自己就是多個具備必定依賴關係,但非同源的類型。設計模式
抽象工廠模式能夠應對這種狀況,它可以產生一系列具備相關依賴關係的類型。
Provide an interface for creating families of related or dependent objects.
— Design Patterns : Elements of Reusable Object-Oriented Software網絡
抽象工廠能夠返回一系列相關或相互依賴對象的接口。另外抽象工廠自身也須要一個接口,這個接口定義中包括返回那些相關對象接口的方法定義。app
其UML類圖以下:
其中IProductA IProductB就是相關或相互依賴對象的接口,實體工廠會生產實現了這些接口的實體產品。IAbstractFactory是抽象工廠的接口,定義了生產IProductA、IProductB的方法。實體工廠自行決定如何實現抽象工廠接口定義的生產方法。異步
實現代碼:ide
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#的工程化實現及擴展》