设计模式学习笔记六:.NET反射工厂
? 1. 簡(jiǎn)述
????通過前面的學(xué)習(xí),我們以傳統(tǒng)的方式實(shí)現(xiàn)了簡(jiǎn)單工廠,工廠方法和抽象工廠,但是有些場(chǎng)合下如此處理,代碼會(huì)變得冗余并且難以維護(hù)。假設(shè)我們要?jiǎng)?chuàng)建交通工具。可以是汽車,火車,輪船等,其結(jié)構(gòu)如下:
?????我們可以采用簡(jiǎn)單工廠,通過參數(shù)指示創(chuàng)建所需要的對(duì)象類型。如果要增加子類,例如卡車和轎車,則必須增加參數(shù)和相應(yīng)的代碼。如果子類層次過多,則會(huì)是程序變得很難維護(hù)。?
????但我們可以采用工廠方法模式來實(shí)現(xiàn),即定義一個(gè)產(chǎn)生交通工具的接口,然后在子類中實(shí)現(xiàn)創(chuàng)建具體子類。代碼如下:
Code
public?interface?ICreateVehicle
????{
?????????Vehicle?CreateCehicle();
????} Code
?public?abstract?class?Vehicle
????{
????} Code
????public?class?Car:Vehicle
????{
????????public?Car()
????????{
????????????Console.WriteLine("創(chuàng)建了一個(gè)Car");
????????}
????} Code
????public?class?Boat:Vehicle?
????{
????????public?Boat()
????????{
????????????Console.WriteLine("創(chuàng)建了一個(gè)Boat");
????????}
????} Code
????public?class?CreateCar:ICreateVehicle
????{
????????ICreateVehicle?成員#region?ICreateVehicle?成員
????????public??Vehicle?CreateCehicle()
????????{
????????????Vehicle?vehicle=new?Car();
????????????return?vehicle;
????????}
????????#endregion
????} Code
????public?class?CreateBoat:ICreateVehicle
????{
????????ICreateVehicle?成員#region?ICreateVehicle?成員
????????public?Vehicle?CreateCehicle()
????????{
????????????Vehicle?vehicle?=?new?Boat();
????????????Console.WriteLine("Car");
????????????return?vehicle;
????????}
????????#endregion
????}
這就是工廠方法。如果希望增加新的交通工具,不僅需要實(shí)現(xiàn)交通工具接口,還需要實(shí)現(xiàn)生產(chǎn)交通工具的工廠方法。
????顯然我們需要幾十種交通工具,則需要幾十個(gè)具體的工廠。而這些類的區(qū)別僅僅是返回相對(duì)應(yīng)的類的實(shí)例,所以位維護(hù)帶來了很大的麻煩。如果需要在接口中增加一個(gè)帶參數(shù)的方法,則所有的子類都需要修改。
在這種場(chǎng)合下,采用抽象工廠與工廠方法沒有區(qū)別,因?yàn)檫@里并不涉及產(chǎn)品線,抽象工廠并不能解決其中的問題,如果每種交通工具都要有對(duì)應(yīng)的車站,則要使用抽象工廠,但是將會(huì)跟復(fù)雜。
有沒有可能將需要?jiǎng)?chuàng)建類的類型傳遞到工廠方法中,由工廠方法根據(jù)類型返回相應(yīng)的實(shí)例?解決這個(gè)問題的關(guān)鍵是需要?jiǎng)討B(tài)的決定需要?jiǎng)?chuàng)建的類,這不是設(shè)計(jì)模式能解決的問題,屬于軟件平臺(tái)的功能范疇。.NET可以提供反射技術(shù)。
我們先看通過反射技術(shù)實(shí)現(xiàn)的簡(jiǎn)化的工廠,代碼如下:
?public?class?CreateVehicleByType:ICreateVehicle
????{
????????ICreateVehicle?成員#region?ICreateVehicle?成員
????????private?Type?VehicleTYpe;
????????public?CreateVehicleByType(string?strType)
????????{
????????????Type?t?=?Type.GetType(strType);
????????????VehicleTYpe?=?t;
????????}
????????public??Vehicle?CreateCehicle()
????????{
????????????ConstructorInfo??objConstrutor?=?VehicleTYpe.GetConstructor(System.Type.EmptyTypes);
????????????Vehicle?c?=?(Vehicle)objConstrutor.Invoke(null);
????????????return?c;
????????}
????????#endregion
???????
????}
在使用是,只要在創(chuàng)建時(shí)帶入需要?jiǎng)?chuàng)建的類的類型:
static?void?Main(string[]?args)
????????{
????????????string?strType?=?"Car";
????????????Vehicle?v;
????????????ICreateVehicle?f?=?null;
????????????if?(strType?==?"Car")
????????????{
????????????????f?=?new?CreateVehicleByType("FactoryVehicle.Car");
????????????}
????????????else?if?(strType?==?"Boat")
????????????{
????????????????f?=?new?CreateVehicleByType("Boat");
????????????}
????????????v?=?f.CreateCehicle();
????????????Console.ReadLine();
????????}
通過反射技術(shù),我們將很多的具體的工廠類簡(jiǎn)化為一個(gè)類,并且新增加類型時(shí)不需要新的工廠類,這樣我們得到簡(jiǎn)化的工廠,可以稱其為“反射工廠”。
2.實(shí)例
???????? 先來看看,大話設(shè)計(jì)模式中的利用反射加抽象工廠的數(shù)據(jù)訪問程序。先來看看反射技術(shù)的基本格式:
Assembly.Load(“程序集名稱”).CreateInstance(“命名空間.類名稱”);
只要在程序頂端寫上using System.Reflection來引用Reflection,就可以采用反射工廠來克服抽象工廠模式的先天不足。下面我們來看通過反射技術(shù)實(shí)現(xiàn)不同數(shù)據(jù)庫的訪問程序.
???????? 先來看結(jié)構(gòu)圖:
?
DataAccess類,用反射技術(shù),取代了抽象工廠中的IFactory,SqlServerFactory和AccessFactory。
????具體代碼:
????
public?class?User
????{
????????private?int?_id;
????????public?int?ID
????????{
????????????get?{?return?_id;?}
????????????set?{?_id?=?value;?}
????????}
????????private?string?_name;
????????public?string?Name
????????{
????????????get?{?return?_name;?}
????????????set?{?_name?=?value;?}
????????}
????}
????public?class?Department
????{
????????private?int?_id;
????????public?int?ID
????????{
????????????get?{?return?_id;?}
????????????set?{?_id?=?value;?}
????????}
????????private?string?_deptName;
????????public?string?DeptName
????????{
????????????get?{?return?_deptName;?}
????????????set?{?_deptName?=?value;?}
????????}
????}
????public?interface?IUser
????{
????????void?Insert(User?user);
????????User?GetUser(int?id);
????}
????public?class?SqlserverUser?:?IUser
????{
????????public?void?Insert(User?user)
????????{
????????????Console.WriteLine("在Sqlserver中給User表增加一條記錄");
????????}
????????public?User?GetUser(int?id)
????????{
????????????Console.WriteLine("在Sqlserver中根據(jù)ID得到User表一條記錄");
????????????return?null;
????????}
????}
????public?class?AccessUser?:?IUser
????{
????????public?void?Insert(User?user)
????????{
????????????Console.WriteLine("在Access中給User表增加一條記錄");
????????}
????????public?User?GetUser(int?id)
????????{
????????????Console.WriteLine("在Access中根據(jù)ID得到User表一條記錄");
????????????return?null;
????????}
????}
????public?interface?IDepartment
????{
????????void?Insert(Department?department);
????????Department?GetDepartment(int?id);
????}
????public?class?SqlserverDepartment?:?IDepartment
????{
????????public?void?Insert(Department?department)
????????{
????????????Console.WriteLine("在Sqlserver中給Department表增加一條記錄");
????????}
????????public?Department?GetDepartment(int?id)
????????{
????????????Console.WriteLine("在Sqlserver中根據(jù)ID得到Department表一條記錄");
????????????return?null;
????????}
????}
????public?class?AccessDepartment?:?IDepartment
????{
????????public?void?Insert(Department?department)
????????{
????????????Console.WriteLine("在Access中給Department表增加一條記錄");
????????}
????????public?Department?GetDepartment(int?id)
????????{
????????????Console.WriteLine("在Access中根據(jù)ID得到Department表一條記錄");
????????????return?null;
????????}
????}
????public?class?DataAccess
????{
????????private?static?readonly?string?AssemblyName?=?"抽象工廠模式";
????????private?static?readonly?string?db?=?"Sqlserver";
????????//private?static?readonly?string?db?=?"Access";
????????public?static?IUser?CreateUser()
????????{
????????????string?className?=?AssemblyName?+?"."?+?db?+?"User";
????????????return?(IUser)Assembly.Load(AssemblyName).CreateInstance(className);
????????}
????????public?static?IDepartment?CreateDepartment()
????????{
????????????string?className?=?AssemblyName?+?"."?+?db?+?"Department";
????????????return?(IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
????????}
????}
調(diào)用代碼:
????????????User?user?=?new?User();
????????????Department?dept?=?new?Department();
????????????IUser?iu?=?DataAccess.CreateUser();
????????????iu.Insert(user);
????????????iu.GetUser(1);
????????????IDepartment?id?=?DataAccess.CreateDepartment();
????????????id.Insert(dept);
????????????id.GetDepartment(1);
????????????Console.Read();
????????}
????現(xiàn)在我們要增加Oracle數(shù)據(jù)訪問,相關(guān)類的增加是不可避免的,這點(diǎn)是無論我們用什么方法都解決不了的,這是擴(kuò)展,依照開發(fā)-封閉原則,對(duì)于擴(kuò)展,我們開放,但對(duì)與修改我們關(guān)閉。就現(xiàn)在的代碼中,我們要換Oracle很容易,只需將db=”Sqlserver”換成db=”O(jiān)racle”。
????現(xiàn)在我們需要增加Product,只需增加三個(gè)與Product相關(guān)的類,再修改一下DataAccess,在其中增加一個(gè)創(chuàng)建Product的方法就可以了。
????現(xiàn)在我們要更換數(shù)據(jù)訪問程序是,我們還需要修改程序,重新編譯,我們可以利用配置文件來解決這個(gè)問題,首先要在我們的項(xiàng)目中添加config文件,內(nèi)容如下:
<?xml?version="1.0"?encoding="utf-8"??>
<configuration>
????<appSettings>
????????<add?key="DB"?value="Sqlserver"/>
????</appSettings>
</configuration>
再在項(xiàng)目中引用
Code
class?DataAccess
????{
????????private?static?readonly?string?AssemblyName?=?"抽象工廠模式";
????????private?static?readonly?string?db?=?ConfigurationManager.AppSettings["DB"];
????????
????????public?static?IUser?CreateUser()
????????{
????????????string?className?=?AssemblyName?+?"."?+?db?+?"User";
????????????return?(IUser)Assembly.Load(AssemblyName).CreateInstance(className);
????????}
????????public?static?IDepartment?CreateDepartment()
????????{
????????????string?className?=?AssemblyName?+?"."?+?db?+?"Department";
????????????return?(IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
????????}
????}
???????? 使用反射工廠的優(yōu)點(diǎn)是極大的減少了工廠類的數(shù)量,降低了代碼的冗余,并且系統(tǒng)更容易擴(kuò)展,增加新類型后,不需要修改工廠類。
???????? 使用反射工廠的代價(jià)是工廠與產(chǎn)品之間的依賴關(guān)系不明顯,由于動(dòng)態(tài)綁定,因此理論上可以用一個(gè)工廠完成很多類型的實(shí)例化,從而使得代碼不容易理解。另外就是增加了測(cè)試難度,因?yàn)閯?chuàng)建是動(dòng)態(tài)完成的。
???????? 采用反射技術(shù)創(chuàng)建的反射工廠可以使系統(tǒng)更靈活,使工廠和產(chǎn)品之間的依賴關(guān)系更小。在.NET的項(xiàng)目中大量的使用了反射工廠取代的傳統(tǒng)的工廠。
總結(jié)
以上是生活随笔為你收集整理的设计模式学习笔记六:.NET反射工厂的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020-3-25
- 下一篇: asp.net如何取得纯客户端控件的值