• 抽象工厂模式 设计模式学习


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

      以下给出抽象工厂方法模式的UML图:

        

      回到《大话设计模式》里面的双数据库访问的例子:

    namespace ConsoleApplication1
    {
        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; }
            }
        }
    
        class Department
        {
            private int _id;
            public int ID
            {
                get { return _id; }
                set { _id = value; }
            }
    
            private string _deptNmae
            {
                get { return _deptNmae; }
                set { _deptNmae = value; }
            }
        }
    
        //IUser接口,用于客户端访问,解除与具体数据库访问的耦合
        interface IUser
        {
            void Insert(User user);
            User GetUser(int id);
        }
    
        class SqlserverUser : IUser 
        {
            public void Insert(User user)
            {
                Console.WriteLine("Sql Server添加一条记录");
            }
    
            public User GetUser(int id)
            {
                Console.WriteLine("Sql Server根据ID得到User表的一条记录");
                return null;
            }
        }
    
        class AccessUser : IUser
        {
            public void Insert(User user)
            {
                Console.WriteLine("在Access中给User表增加一条记录");
            }
    
            public User GetUser(int id)
            {
                Console.WriteLine("在Access中根据ID得到User表的一条记录");
                return null;
            }
        }
    
        interface IDepartment
        {
            void Insert(Department department);
            Department GetDepartment(int id);
        }
    
        class SqlserverDepartment : IDepartment
        {
            public void Insert(Department department)
            {
                Console.WriteLine("在Sqlserver中给Department表插入一条记录");
            }
    
            public Department GetDepartment(int id)
            {
                Console.WriteLine("在Sqlserver中根据ID得到Department表的一条记录");
                return null;
            }
        }
    
        class AccessDepartment : IDepartment 
        {
            public void Insert(Department department)
            {
                Console.WriteLine("在Access中给Department表插入一条记录");
            }
    
            public Department GetDepartment(int id)
            {
                Console.WriteLine("在Access中根据ID得到Department表的一条记录");
                return null;
            }
        }
    
        interface IFactory
        {
            IUser CreateUser();
    
            IDepartment CreateDepartment();
        }
    
        //SQLServer实例化工厂,负责实例化SqlserverUser和SqlserverDepartment
        class SqlServerFactory : IFactory
        {
            public IUser CreateUser()
            {
                return new SqlserverUser();
            }
    
            public IDepartment CreateDepartment()
            {
                return new SqlserverDepartment();
            }
        }
    
        //Access实例化工厂,负责实例化AccessUser和AccessDepartment
        class AccessFactory : IFactory
        {
            public IUser CreateUser()
            {
                return new AccessUser();
            }
    
            public IDepartment CreateDepartment()
            {
                return new AccessDepartment();
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                IFactory factory = new SqlServerFactory();
    
                IUser iu = factory.CreateUser();    //获得数据库User访问类的对象
                iu.Insert(new User());
                iu.GetUser(1);
    
                IDepartment idepartment = factory.CreateDepartment();   //获得数据库Department访问类的对象
                idepartment.Insert(new Department());
                idepartment.GetDepartment(1);
    
                Console.ReadKey();
            }
        }  
    }

      其实以上代码就叫做抽象工厂模式了,当只有一个User表的时候,就叫工厂方法模式。当有了多个表了,就叫抽象工厂模式。但是以上代码是非常不好的,为什么?例如当你还要增加一个Project表的时候,就需要增加三个类,IProject、SqlserverProject、AccessProject,同时还需要更改IFactory、SqlserverFactory、AccessFactory。增加一张表就要更改三个类,这个是比较悲剧的。

      因此,以下给出一个用简单工厂模式来优化抽象工厂模式的代码:

    namespace ConsoleApplication1
    {
        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; }
            }
        }
    
        class Department
        {
            private int _id;
            public int ID
            {
                get { return _id; }
                set { _id = value; }
            }
    
            private string _deptNmae
            {
                get { return _deptNmae; }
                set { _deptNmae = value; }
            }
        }
    
        //IUser接口,用于客户端访问,解除与具体数据库访问的耦合
        interface IUser
        {
            void Insert(User user);
            User GetUser(int id);
        }
    
        class SqlserverUser : IUser 
        {
            public void Insert(User user)
            {
                Console.WriteLine("Sql Server添加一条记录");
            }
    
            public User GetUser(int id)
            {
                Console.WriteLine("Sql Server根据ID得到User表的一条记录");
                return null;
            }
        }
    
        class AccessUser : IUser
        {
            public void Insert(User user)
            {
                Console.WriteLine("在Access中给User表增加一条记录");
            }
    
            public User GetUser(int id)
            {
                Console.WriteLine("在Access中根据ID得到User表的一条记录");
                return null;
            }
        }
    
        interface IDepartment
        {
            void Insert(Department department);
            Department GetDepartment(int id);
        }
    
        class SqlserverDepartment : IDepartment
        {
            public void Insert(Department department)
            {
                Console.WriteLine("在Sqlserver中给Department表插入一条记录");
            }
    
            public Department GetDepartment(int id)
            {
                Console.WriteLine("在Sqlserver中根据ID得到Department表的一条记录");
                return null;
            }
        }
    
        class AccessDepartment : IDepartment 
        {
            public void Insert(Department department)
            {
                Console.WriteLine("在Access中给Department表插入一条记录");
            }
    
            public Department GetDepartment(int id)
            {
                Console.WriteLine("在Access中根据ID得到Department表的一条记录");
                return null;
            }
        }
    
        class DataAccess
        {
            private static readonly string db = "SqlServer";    //事先就设置好的数据库
            //private static readonly string db = "Access";     //也就是说,更改数据库改的是这里了 
    
            public static IUser CreateUser()    //这是第一个User的简单工厂
            {
                IUser result = null;
                switch (db)         //根据db的设置实例化不同的User数据库访问对象
                {
                    case "SqlServer":
                        result = new SqlserverUser();
                        break;
                    case "Access":
                        result = new AccessUser();
                        break;
                }
                return result;
            }
    
            public static IDepartment CreateDepartment()    //这是Department的简单工厂
            {   
                IDepartment result = null;
                switch (db)
                {
                    case "Sqlserver":
                        result = new SqlserverDepartment();
                        break;
                    case "Access":
                        result = new AccessDepartment();
                        break;
                }
                return result;
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                IUser iu = DataAccess.CreateUser();    //获得数据库User访问类的对象,要改数据库就要改DataAccess里面的设置
                iu.Insert(new User());
                iu.GetUser(1);
    
                IDepartment idepartment = DataAccess.CreateDepartment();   //获得数据库Department访问类的对象,这里没有依赖SqlserverFactory或AccessFactory了
                idepartment.Insert(new Department());
                idepartment.GetDepartment(1);
    
                Console.ReadKey();
            }
        }  
    }

      经过简单工厂模式优化之后,客户端就不再依赖于SqlserverFactory或AccessFactory了,带到了解耦的目的。如果要添加一个Project,只需要添加响应类,但改就只需要修改DataAccess就可以了(在DataAccess里面在添加一个简单工厂)。很明显者不是最终方案,因为简单工厂方法还是要修改,switch case。

      以下还有通过反射实现的更加好的方案:

    namespace ConsoleApplication1
    {
        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; }
            }
        }
    
        class Department
        {
            private int _id;
            public int ID
            {
                get { return _id; }
                set { _id = value; }
            }
    
            private string _deptNmae
            {
                get { return _deptNmae; }
                set { _deptNmae = value; }
            }
        }
    
        //IUser接口,用于客户端访问,解除与具体数据库访问的耦合
        interface IUser
        {
            void Insert(User user);
            User GetUser(int id);
        }
    
        class SqlserverUser : IUser 
        {
            public void Insert(User user)
            {
                Console.WriteLine("Sql Server添加一条记录");
            }
    
            public User GetUser(int id)
            {
                Console.WriteLine("Sql Server根据ID得到User表的一条记录");
                return null;
            }
        }
    
        class AccessUser : IUser
        {
            public void Insert(User user)
            {
                Console.WriteLine("在Access中给User表增加一条记录");
            }
    
            public User GetUser(int id)
            {
                Console.WriteLine("在Access中根据ID得到User表的一条记录");
                return null;
            }
        }
    
        interface IDepartment
        {
            void Insert(Department department);
            Department GetDepartment(int id);
        }
    
        class SqlserverDepartment : IDepartment
        {
            public void Insert(Department department)
            {
                Console.WriteLine("在Sqlserver中给Department表插入一条记录");
            }
    
            public Department GetDepartment(int id)
            {
                Console.WriteLine("在Sqlserver中根据ID得到Department表的一条记录");
                return null;
            }
        }
    
        class AccessDepartment : IDepartment 
        {
            public void Insert(Department department)
            {
                Console.WriteLine("在Access中给Department表插入一条记录");
            }
    
            public Department GetDepartment(int id)
            {
                Console.WriteLine("在Access中根据ID得到Department表的一条记录");
                return null;
            }
        }
    
        class DataAccess
        {
            private static readonly string AssemblyName = "ConsoleApplication1";    //字符串为程序集的名字
            private static readonly string db = ConfigurationManager.AppSettings["DB"];
    
            public static IUser CreateUser()
            {
                string className = AssemblyName + "." + db +"User"; //拼接SqlserverUser类或AccessUser类所在的位置
                return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);    //反射创建实例
            }
    
            public static IDepartment CreateDepartment()
            {
                string className = AssemblyName + "." + "SqlserverDepartment";
                return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                IUser iu = DataAccess.CreateUser();    //获得数据库User访问类的对象,要改数据库就要改DataAccess里面的设置
                iu.Insert(new User());
                iu.GetUser(1);
    
                IDepartment idepartment = DataAccess.CreateDepartment();   //获得数据库Department访问类的对象
                idepartment.Insert(new Department());
                idepartment.GetDepartment(1);
    
                Console.ReadKey();
            }
        }  
    }

      配置文件App.config代码:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <add key="DB" value="Access" />
      </appSettings>
    </configuration>

      以上就是反射+抽象工厂的方法, 还是非常强大的,强大到什么程度呢?例如上面的代码,要修改数据库访问对象例如将Sqlserver改为Access根本不需要改动程序重新编译,只需要改动App.config就可以了。其实这里的反射只是改进了简单工厂模式而已,与抽象工厂没太大的关系。要记住,所有在用到简单工厂的地方都可以考虑用反射技术来去除switch解除分支判断所带来的耦合。

      在以上的代码中,要增加一个Project表的话,只需要添加三个Project相关的类(扩展),再修改DataAccess,在其中增加一个CreateProject()方法就可以了。

  • 相关阅读:
    Python shutil模块
    configparser模块来生成和修改配置文件
    用random模块实现验证码
    python 正则re模块
    python 装饰器
    python迭代器和生成器
    python替换一个文件里面的特定内容
    广告资源收集
    Java 语言中 Enum 类型的使用介绍
    FreeMarker + xml 导出word
  • 原文地址:https://www.cnblogs.com/kissdodog/p/2967645.html
Copyright © 2020-2023  润新知