設計模式----抽象工廠

守望陽光01發表於2019-03-31

今天,我們接著來說說設計模式中的抽象工廠模式,繼上次工廠模式之後我們來說說他們中的大佬抽象工廠。

首先,還是想象一個場景,今天我們用到的是我們專案中經常要用的切換資料庫;

例如,一開始專案用的是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; }
        }
    }

這裡我們新建兩個實體,UserDepartMent,各有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表增加一條記錄");
        }
    }

同樣是accessSQLserver各自實現,這裡我們用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類,如果你想建立AccessUserAccessDepartment類,可以修改我們之前在app.config配置檔案中的SQLserver修改成Access,然後執行程式看看它實現的方法吧,這裡就不再多說,留給你們去實現了。這裡我們其實是通過名稱來區分資料庫的,其實只是為了說明反射的用法。好了,反射+抽象工廠就說到這了

 

相關文章