系統架構技能之設計模式—抽象工廠模式
一、上篇回顧
上篇我們主要講述了簡單工廠模式和工廠模式。并且分析了每種模式的應用場景和一些優缺點,我們現在來回顧一下:
簡單工廠模式:一個工廠負責所有類型對象的創建,不支持無縫的新增新的類型對象的創建。
工廠模式:多個工廠負責多個類型對象的創建,每個工廠只負責具體類型對象的創建,支持無縫的新增類型對象的創建,需要實現工廠接口類和具體的類型對象類。
我們來簡單的對比下這2個模式的優缺點:
模式名稱 | 優點 | 缺點 |
簡單工廠模式 | 一個工廠負責所有對象的創建,簡單靈活 | 不符合高內聚的原則,不支持無縫的擴展 |
工廠模式 | 可以無縫的新增類型,每個工廠職責單一,符合高內聚的原則 | 工廠類太多,難以維護。 |
工廠模式,很優雅的解決了應用程序使用對象時的無限new()的操作,同時降低了系統應用之間的耦合性,提高了系統的可維護性和適應性。
二、摘要
本文主要是針對創建型模式中的抽象工廠模式進行講述,抽象工廠模式是在簡單工廠模式的基礎上擴展而成的新模式,將簡單工廠中的對象的創建過程進行了很優雅的動態配置來完成無縫的擴展,當然通過一些擴展,可以構建出可支持動態新增或者刪除對象的抽象工廠模式。本文將會給出具體的實現方案,相比工廠模式,抽象工廠模式是一個工廠負責多個對象的創建,返回的具體的類型是這個對象的抽象類型。這樣,在客戶端引用的時候只需要使用這個工廠返回的對象類型,抽象工廠會自動根據對象的類型動態的創建這個類型對象的實例。大體的過程如下:
上面的圖片呢,主要是針對經典的抽象工廠模式給出了一個實現草圖的模擬,而我們在實際的項目中可能并不希望給出這么多的抽象工廠工廠實現,我只想給出一個通用的抽象工廠實現,通過靜態方法直接調用,返回我想要的對象類型的實例,而且這個對象類型是可以動態配置的,那么我們如何做到呢?這就是本篇需要討論的實現方案。本篇將會從以下幾點進行講述抽象工廠模式:
1、抽象工廠模式的簡單實例代碼-這里給出的是經典的抽象工廠模式實例代碼。我們從經典的實例代碼中可以看出這個工廠模式的一些缺點。
2、根據經典工廠模式的缺點,我們給出改進的方案,進一步給出項目中可以使用的通用方案實現。
3、給出上篇中的通過委托來實現的工廠模式方案。
4、通過特性+反射的形式來動態的創建對象。
三、本文大綱
a、上篇回顧。
b、摘要。
c、本文大綱。
d、抽象工廠模式的特點及使用場景。
e、抽象工廠模式的實現方案。
f、抽象工廠模式使用總結。
g、系列進度。
h、下篇預告。
四、抽象工廠模式的特點及使用場景
抽象工廠可以說是三類工廠模式中使用最廣泛的,也是最受大家喜愛的模式之一,因為抽象工廠模式解決了一系列相互依賴的對象或者有組合關系的對象的創建過程。舉個簡單的例子來說,我們以電腦的顯卡和風扇來說吧,我們知道顯卡一般在玩游戲的時候,由于渲染圖形會產生大量的熱量,如果沒有好的風扇那么可能無法達到好的散熱的效果,這個時候我們可以把顯卡和風扇的創建放在一個抽象工廠中進行創建,因為這2個對象是具有依賴關系的對象,那么我們來給出這個例子的完整實例代碼:
先看看2個對象類型的接口和抽象工廠的接口定義:
/// 定義顯卡抽象對象接口
/// </summary>
public interface IDisplayCard
{
}
/// <summary>
/// 定義顯卡風扇抽象對象接口
/// </summary>
public interface IDisplayFan
{
}
/// <summary>
/// 定義顯卡設備抽象工廠接口
/// </summary>
public interface IAbstractDriveFactory
{
IDisplayCard CreateDisplayCard();
IDisplayFan CreateDisplayFan();
}
我們來看看具體類型的實現和抽象工廠的具體實現:
/// 定義華碩顯卡的具體對象
/// </summary>
public class DisplayCardAsus : IDisplayCard
{
}
/// <summary>
/// 華碩顯卡配套風扇
/// </summary>
public class DisplayFanAsus : IDisplayFan
{
}
/// <summary>
/// 華碩顯卡具體實現工廠
/// </summary>
public class DriveFactoryAsus : IAbstractDriveFactory
{
IDisplayCard CreateDisplayCardAsus()
{
return new DisplayCardAsus();
}
IDisplayFan CreateDisplayFanAsus()
{
return new DisplayFanAsus();
}
}
通過上面的代碼,我們給出了抽象工廠的一個經典實例的實現方案,當然這不是我們開發中使用的實際形式,那么實際我們在項目中如何使用這個抽象工廠模式呢?我們一般是改進的方案去使用這個抽象工廠模式,我們如何改進呢?對于目前的,如果我不光創建顯卡設備和配套的風扇設備,我還想創建其他的類型的東西,這時候可能我們定義的抽象工廠就無法滿足具有相互依賴或者組合關系的對象類型實例的創建工作了,那么我們如何改進呢,這就是下面要講述的幾類方案。
五、抽象工廠模式的實現方案
5.1、通過配置文件來實現
- 我們先給出基于上面的經典抽象工廠的一個改進的方案,可以支持動態配置的抽象工廠,一個工廠負責動態的創建一些列的可動態配置的對象列表,我們如何做呢,我想一提到配置。大家都知道要么是通過XML文件來實現或者是通過泛型集合來做。我們這里可以提供的方案是這樣的,通過工廠初始化時從配置文件中讀取配置項,構造一個字典,然后從這個字典中查詢要創建的類型是否在字典中,如果在字典中存在則創建這個類型的對象,否則返回NULL,我們這里通過泛型來實現。
- 我們來看看具體的代碼實現吧:
/// 定義抽象工廠接口
/// </summary>
public interface IAbstractFactory
{
/// <summary>
/// 通用的泛型對象創建工廠
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T Create<T>();
}
給出具體的實現這個接口的抽象工廠類:
/// 具體的通用工廠實現
/// </summary>
public class AbstractFactory : IAbstractFactory
{
private static readonly IDictionary<Type, Type> instances = null;
public static AbstractFactory()
{
//從具體的配置項中讀取,從配置文件中讀取或者通過某個方法來硬編碼實現等。
//這里推薦的做飯是從配置文件中讀取。
instances = new Dictionary<Type, Type>();
instances.Add(Type.GetType(""), Type.GetType(""));
instances.Add(Type.GetType(""), Type.GetType(""));
}
public T Create<T>()
{
if (!instances.ContainsKey(typeof(T)))
return default(T);
Type typeInstance = instances[typeof(T)];
T obj = (T)Activator.CreateInstance(typeInstance);
return obj;
}
}
- 通過上面給出的代碼,基本上可以滿足一般項目的需求,大家當然有好的思路和建議也可以提出,給出更好的改進方案,下面我給出大概的配置文件格式,其實就是父子級節點,父級節點是負責創建的工廠
- 類,那么這個父節點下的子節點就是工廠要創建的具體的對象類型。
上圖中描述的思路,我們大概知道了,對應這樣的一個支持多個具有依賴關系或者組合關系的對象的動態抽象工廠的實現,那么如果我們想實現支持多個具有依賴關系或者組合關系的不同的創建形式的通用創建工廠時,我們如何來做呢?同上面的思路,只不過我們外部需要再添加一個字典,負責類型和抽象工廠的映射,即抽象工廠可以創建的字典列表及抽象工廠具體實例類型之間的鍵值對關系,或者通過配置文件來組織父子級的關系。我們大概的看下配置文件的組織吧:
<AbstractFactory>
<FactorySections>
<FactorySection name="ProductFactory" type="DesignPattern.ProductFactory">
<ObjectInstance name="" type=""/>
<ObjectInstance name="" type=""/>
<ObjectInstance name="" type=""/>
<ObjectInstance name="" type=""/>
</FactorySection>
<FactorySection name="FoodFactory" type="DesignPattern.FoodFactory">
<ObjectInstance name="" type=""/>
<ObjectInstance name="" type=""/>
<ObjectInstance name="" type=""/>
<ObjectInstance name="" type=""/>
</FactorySection>
<FactorySection name="BookFactory" type="DesignPattern.BookFactory">
<ObjectInstance name="" type=""/>
<ObjectInstance name="" type=""/>
<ObjectInstance name="" type=""/>
<ObjectInstance name="" type=""/>
</FactorySection>
</FactorySections>
</AbstractFactory>
那么具體的抽象工廠的代碼又如何組織呢?如下形式:
/// 具體的通用工廠實現
/// </summary>
public class AbstractFactory : IAbstractFactory
{
/// <summary>
/// 工廠與工廠能夠創建的對象類型字典之間的映射字典
/// </summary>
private static readonly IDictionary<Type, Dictionary<Type, Type>> typeMapper = null;
private Type factoryType = null;
public static AbstractFactory()
{
//從具體的配置項中讀取,從配置文件中讀取或者通過某個方法來硬編碼實現等。
//這里推薦的做飯是從配置文件中讀取。
//根據配置文件中的ObjectInstance 節點放在對應的工廠下的字典中
//每個工廠節點FactorySection 就會創建一個字典,并且將這個工廠能夠創建的類型放在這個字典中
typeMapper = new Dictionary<Type, Dictionary<Type, Type>>();
}
public AbstractFactory(string typeName)
{
this.factoryType = Type.GetType(typeName);
}
public T Create<T>()
{
if(typeMapper.ContainsKey(this.factoryType))
return default(T);
Dictionary<Type, Type> instances = typeMapper[this.factoryType];
if (!instances.ContainsKey(typeof(T)))
return default(T);
Type typeInstance = instances[typeof(T)];
T obj = (T)Activator.CreateInstance(typeInstance);
return obj;
}
}
通過上面的代碼我們就給出了一個通用的抽象工廠的可行的解決方案。
5.2、通過委托來實現工廠模式
我們先要定義一個委托:
/// <summary>
/// 基于這個委托的工廠實現方案,具體的通用工廠實現。
/// </summary>
public class DegelateFactory
{
private DelegateFunctionHandler handler = null;
public static DelegateFunctionHandler Create()
{
if (handler == null)
handler = new DelegateFunctionHandler(this.Test);
return handler;
}
public string Test(string name)
{
return "Test!";
}
}
工廠返回一個委托類型的對象,當然我上面為了簡單給出的test方法其實就是工廠內部的方法,當然這里還可以進行相應的改進,也可以通過配置文件來完成,通過配置文件把相應相應的委托事件方法,通過配置來通過工廠動態的創建。下面給出個思路吧,具體的實現我就不貼出來了:
六、抽象工廠模式使用總結
通過上面的實現方式和思路,我們來對比一下抽象工廠、工廠模式、簡單工廠模式之間的差異和相同點。
相同點:
1、都是為客戶調用程序與具體的對象類型之間提供了一個解耦作用,這里怎么說呢?其實就是應用程序不關心這個對象是怎么出來的,只關系如何使用這個對象,而且以后就算對象發生變化,那么也不需要修改用戶應用程序的代碼。
2、提高了程序的可維護性和低耦合性。
異同點:
1、簡單工廠模式:是簡單的一些列沒有任何依賴關系的對象的創建,內部包含復雜的邏輯關系,一半是通過配置或者參數來進行創建對象,適合對象類型不多,并且不會經常新增的情況下。
工廠模式:每個工廠負責具體類型對象的創建,提供了可以動態新增產品類型的創建,并不需要修改現有的程序就可以無縫的新增產品類型。
抽象工廠模式:支持動態的新增對象類型和新增工廠類型,實現多種依賴關系的對象或者組合關系的創建,適合現有項目中的對象創建過程。
2、簡單工廠模式:內部邏輯復雜,不符合高內聚的原則。
工廠模式:每次新增一個對象類型,就必須新增一個對應的創建工廠,無疑這是一個非常大的工作量。
抽象工廠模式:是在簡單工廠模式的基礎上經過改進具有前2個模式的優點,又屏蔽了他們的一些缺點。
當然我們在具體的項目中,還是需要具體的情況具體分析,一般情況下,我們對于這種數據庫平滑遷移時,簡單工廠可能比其他2類工廠更容易做,也很靈活。