• 大话设计模式-抽象工厂模式


    抽象工厂模式

    抽象工厂模式提供一个创建一系列相关或互相依赖的接口,而无需再指定他们具体的类。

    最大的好处是易于交换产品系列,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,这使得改变一个应用的具体工厂变得非常容易,他只需要改变具体工厂即可使用不同的产品配置。

    他让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。


    访问数据库

    数据类:User/Department

    class User{
        public int ID { get; set; }
        public string Name { get; set; }
    }
    class Department{
        public int ID { get; set; }
        public string Name { get; set; }
    }

    数据接口:IUser/IDepartment

    用于客户端访问,解除与具体数据库访问的耦合。

    interface IUser{
        void Insert(User user);
        void GetUser(int id);
    }
    interface IDepartment{
        void Insert(Department department);
        void GetDepartment(int id);
    }

    接口实现类:MySQL/SQLServer User/Department

    分别实现MySQL和SQLServer两种数据库的对用户表和部门表的数据操作。每种表的操作封装在一个类中。

    class SQLServerUser : IUser
    {
        public void Insert(User user) => Console.WriteLine("在SQLServer中给User表插入一条记录");
        public void GetUser(int id) => Console.WriteLine("在SQLServer中根据ID查询User表得到一条记录");
    }
    class MySQLUser : IUser
    {
        public void Insert(User user) => Console.WriteLine("在MySQL中给User表插入一条记录");
        public void GetUser(int id) => Console.WriteLine("在MySQL中根据ID查询查询User表得到一条记录");
    }
    class SQLServerDepartment : IDepartment
    {
        public void Insert(Department department) => Console.WriteLine("在SQLServer中给Department表插入一条记录");
        public void GetDepartment(int id) => Console.WriteLine("在SQLServer中根据ID查询Department表得到一条记录");
    }
    class MySQLDepartment : IDepartment
    {
        public void Insert(Department department) => Console.WriteLine("在MySQL中给Department表插入一条记录");
        public void GetDepartment(int id) => Console.WriteLine("在MySQL中根据ID查询Department表得到一条记录");
    }

    工厂接口:IFactory

    声明了创建不同数据库都要实现的方法

    interface IFactory
    {
        IUser CreateUser();
        IDepartment CreateDepartment();
    }

    具体工厂类:MySQL/SQLServer Factory

    为不同数据库创建对应的对表的操作封装的类的实例。

    class SQLServerFactory : IFactory{
        public IUser CreateUser() => new SQLServerUser();
        public IDepartment CreateDepartment() => new SQLServerDepartment();
    }
    class MySQLFactory : IFactory{
        public IUser CreateUser() => new MySQLUser();
        public IDepartment CreateDepartment() => new MySQLDepartment();
    }

    测试类:Program

    //声明工厂,选择SQLServer工厂
    IFactory factory = new SQLServerFactory();
    //声明用户数据类,创建SQLServer的封装了创建对用户表操作的类的实例
    User user = new User();
    IUser iuser = factory.CreateUser();
    //执行类中封装的对用户表操作的方法
    iuser.Insert(user);
    iuser.GetUser(1);
    //部门数据类同上
    Department department = new Department();
    IDepartment idepartment = factory.CreateDepartment();
    idepartment.Insert(department);
    idepartment.GetDepartment(1);
    //测试结果
    在SQLServer中给User表插入一条记录
    在SQLServer中根据ID查询User表得到一条记录
    在SQLServer中给Department表插入一条记录
    在SQLServer中根据ID查询Department表得到一条记录

    使用简单工厂来改进抽象工厂

    去除IFactory、SQLServerFactory和MySQLFactory三个工厂类。取而代之的是DataAccess类,用一个简单工厂模式来实现。

    数据访问类:DateAccess

    数据库名称可以替换成需要的,由于数据库名称的实现设置,所以在静态方法中可以根据选择实例化出相应的对象。

    class DateAccess{
        private static readonly string db = "SQLServer";
        public static IUser CreateUser(){
            IUser result = null;
            switch (db){
                case "SQLServer":
                    result = new SQLServerUser();
                    break;
                case "MySQL":
                    result=new MySQLUser();
                    break;
            }
            return result;
        }
        public static IDepartment CreateDepartment(){
            IDepartment result = null;
            switch (db){
                case "SQLServer":
                    result = new SQLServerDepartment();
                    break;
                case "MySQL":
                    result = new MySQLDepartment();
                    break;
            }
            return result;
        }
    }

    测试类:Program

    直接使用DataAccess得到实际的数据库访问实例,不需要任何依赖。

    User user = new User();
    IUser iuser = DateAccess.CreateUser();
    iuser.Insert(user);
    iuser.GetUser(1);
    
    Department department = new Department();
    IDepartment idepartment = DateAccess.CreateDepartment();
    idepartment.Insert(department);
    idepartment.GetDepartment(1);

    用反射加抽象工厂的数据访问程序

    Assembly.Load("程序集名称").CreateInstance("命名空间.类名");

    数据访问类:DataAccess

    如果增加Orac数据访问,相关类的增加是不可避免的,但是根据开放-封闭原则,应该开放扩展,关闭修改。现在只需修改private static readonly string db = "SQLServer";就可以创建不同的实例了。

    using System.Reflection;
    class DateAccess{
        private static readonly string AssemblyName = "FactoryTest";
        private static readonly string db = "SQLServer";
        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);
        }
    }

    用反射加配置文件实现数据访问程序

    利用配置文件来解决更改DataAccess的问题。在配置文件中写明是哪个数据库。读取文件来给db字符串赋值。

    添加一个App.config文件

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
        </startup>
        <appSettings>
          <add key="DB" value="SQLServer"/>
        </appSettings>
    </configuration>

    数据访问类:DataAccess

    在程序开头增加using System.Configuration;然后更改DataAccess类的字段DB的赋值代码。

    class DateAccess{
        private static readonly string AssemblyName = "FactoryTest";
        private static readonly string db = ConfigurationSettings.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);
        }
    }

    所有用在简单工厂的地方都可以考虑用反射技术来去除switc或if,接触分支判断带来的耦合。

  • 相关阅读:
    HDU4529 郑厂长系列故事——N骑士问题 —— 状压DP
    POJ1185 炮兵阵地 —— 状压DP
    BZOJ1415 聪聪和可可 —— 期望 记忆化搜索
    TopCoder SRM420 Div1 RedIsGood —— 期望
    LightOJ
    LightOJ
    后缀数组小结
    URAL
    POJ3581 Sequence —— 后缀数组
    hdu 5269 ZYB loves Xor I
  • 原文地址:https://www.cnblogs.com/errornull/p/10060193.html
Copyright © 2020-2023  润新知