今天,我們接著來說說設計模式中的抽象工廠模式,繼上次工廠模式之後我們來說說他們中的大佬抽象工廠。
首先,還是想象一個場景,今天我們用到的是我們專案中經常要用的切換資料庫;
例如,一開始專案用的是mysql資料庫,後來又要切換成SQLserver資料庫
今天,我們就用這個場景來學習一下反射+抽象工廠模式。
使用的dataBase優先的話我們當然是在專案中新建實體了
class DepartMent { private int _id; public int ID { get { return _id; } set { _id = value; } } private string name; public string Name { get { return name; } set { name = value; } } }
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; } } }
這裡我們新建兩個實體,User和DepartMent,各有Id和Name兩個屬性,就是這麼簡單。
然後接下來我們要幹嘛呢(^_^),當然是抽象啦,設計模式怎麼少得了抽象呢
實體嘛,無非就是CRUD,所以我們就抽象他們
interface IDepartment { void Insert(DepartMent departMent); DepartMent GetDepart(int id); }
這裡我們抽象出兩個方法,獲取物件和新增物件方法,細心的你應該會發現這裡是寫死的,我們的專案中,不可能只有一個表的吧,按照這種寫法的話那豈不是每個表都要新建一個類嗎,那豈不是型別數量要爆炸啊(汗顏)
這裡我們不急,我們首先看一個是怎麼實現的,學會了一個,其他還不是一樣的道理嗎(搬磚),接下來就是要去實現了
class AccessDepartment : IDepartment { public DepartMent GetDepart(int id) { Console.WriteLine("在Access中根據ID得到Department表一條記錄"); return null; } public void Insert(DepartMent departMent) { Console.WriteLine("在Access中給Department表增加一條記錄"); } }
class SqlserverDepartment : IDepartment { public DepartMent GetDepart(int id) { Console.WriteLine("在SQL server中根據ID得到DepartMent表一條記錄"); return null; } public void Insert(DepartMent departMent) { Console.WriteLine("在SQL server 中給DepartMent表增加一條記錄"); } }
這裡我們新建了兩個類,分別代表access資料庫和SQLserver資料庫,分別實現IDepartment介面,好了,實現了抽象介面,接下來就是建立了
class DataAccess { private static readonly string AssemblyName = "抽象工廠模式"; private static readonly string db = ConfigurationManager.AppSettings["DB"]; public static IDepartment CreateDepartment() { string className = AssemblyName + "." + db + "Department"; return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className); } }
建立一個DataAccess類,這裡要解釋下,首先AssemblyName這個屬性是我們的名稱空間,也就是我們的程式集名稱,然後db是我們寫在app.config配置檔案中的資料庫名稱
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="DB" value="Sqlserver"/> </appSettings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> </configuration>
當你想要切換資料庫的時候,我們只需要修改這裡的value值就可以達到切換資料庫的功能,不用修改任何程式碼,是不是感覺有些小興奮呢
CreateDepartment方法中className是用來組合我們要建立的類的名稱,然後通過反射去動態的建立
最後,我們看看如何呼叫它
class Program { static void Main(string[] args) { DepartMent departMent = new DepartMent(); IDepartment id = DataAccess.CreateDepartment(); id.Insert(departMent); id.GetDepart(1); } }
例項化一個DepartMent實體,然後我們通過DataAccess類中的CreateDepartment方法去建立IDepartment,實際上我們建立的是SqlserverDepartment類,建立完成之後就可以使用方法執行資料庫操作了
到這裡,一個實體我們就學完了,前面我們說了專案中我們不會是一個實體,有很多個實體,那怎麼辦呢(看程式碼)
interface IUser<T> { void Insert(T user); T GetUser(int id); }
我們可以抽象一個泛型介面IUser(這裡名字不重要,只是我們前面寫了User實體,所以借用一下),然後我們實現它
class SqlserverUser:IUser<User> { public void Insert(User user) { Console.WriteLine("在SQL server 中給User表增加一條記錄"); } public User GetUser(int id) { Console.WriteLine("在SQL server中根據ID得到User表一條記錄"); return null; } public string GetTypeName(User t) { throw new NotImplementedException(); } }
class AccessUser : IUser<User> { public User GetUser(int id) { Console.WriteLine("在Access中根據ID得到User表一條記錄"); return null; } public void Insert(User user) { Console.WriteLine("在Access中給User表增加一條記錄"); } }
同樣是access和SQLserver各自實現,這裡我們用User來做例子,你也可以用Depart或者其他來,這樣是不是就解決了呢,然後依葫蘆畫瓢
public static T CreateUser<T>() { string Name = typeof(T).GenericTypeArguments[0].Name; string className = AssemblyName + "." + db + Name; return (T)Assembly.Load(AssemblyName).CreateInstance(className); }
我們在DataAccess類中新增一個方法CreateUser<T>泛型方法,這裡Name是獲取傳入的引數型別的名稱,然後同樣是組合程式集名稱通過反射建立
同樣,我們來看看如何使用
User user = new User(); IUser<User> iu = DataAccess.CreateUser<IUser<User>>(); iu.Insert(user); iu.GetUser(1);
這裡例項化一個User物件,然後同樣的道理通過DataAccess類的CreateUser泛型方法去建立,這裡我們實際建立的是SqlserverUser類,如果你想建立AccessUser和AccessDepartment類,可以修改我們之前在app.config配置檔案中的SQLserver修改成Access,然後執行程式看看它實現的方法吧,這裡就不再多說,留給你們去實現了。這裡我們其實是通過名稱來區分資料庫的,其實只是為了說明反射的用法。好了,反射+抽象工廠就說到這了