设计模式----抽象工厂

今天,我们接着来说说设计模式中的抽象工厂模式,继上次工厂模式之后我们来说说他们中的大佬抽象工厂。

首先,还是想象一个场景,今天我们用到的是我们项目中经常要用的切换数据库;

例如,一开始项目用的是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,然后运行程序看看它实现的方法吧,这里就不再多说,留给你们去实现了。这里我们其实是通过名称来区分数据库的,其实只是为了说明反射的用法。好了,反射+抽象工厂就说到这了

原文地址:https://www.cnblogs.com/liuhuimh/p/10631102.html