zoukankan      html  css  js  c++  java
  • 设计模式——抽象工厂之反射“+”

    前言

      在学习设计模式时,我接触到了简单工厂模式、工厂模式和抽象工厂模式,敲完三个模式的小例子,还是感觉抽象工厂模式比较好。代码与代码之间,类与类,接口与接口之间耦合显然降到了至今的最低。大大提高了复用性和后期软件的维护,方便了用户需求的更改。

    内容

      抽象工厂设计模式中,最为典型的是反射“+”思想。下面举例子说明:

    背景

      给一家企业做的电子商务网站,使用SQLServer作为数据库的,应该说上线后除了开始有些小问题,基本都还可以,而后,公司接到了另外一家公司类似的需求的项目,但是这个公司采用比较省钱的方式,租用了一个空间,只能用Access,不能用SQL Server。目标是将原来用SQL Server作为数据库的代码改为用Access作为数据库的代码。

    实践

      这样的要求就要看原来的代码了,如果原代码之间耦合度够低,那么转换起来不至于那么费劲。且看用抽象工厂模式写的代码:

    用户接口部分:

    //作者:周丽同
        //用户接口
        interface IUser
        {
            void Insert(User user);
            User GetUser(int id);
        }
        //sqlserverUser类
        class SqlserverUser : IUser
        {
            public void Insert(User user)
            {
                Console.WriteLine("在SQL中User表中增加了一条记录");
            }
            public User GetUser(int id)
            {
                Console.WriteLine("在SQL Server中根据ID得到User表一条记录");
                return null;
            }
        }
    
        //AccessUser类
        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);
        }
        //sqlserverDepartment
        class SqlserverDepartment:IDepartment
        {
            public void Insert (Department department)
            {
                Console.WriteLine("在sql server中给department表添加了一条记录");
            }
            public Department GetDepartment(int id)
            {
                Console.WriteLine("在sql server中根据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 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 _deptname;
            public string DeptName
            {
                get { return _deptname; }
                set { _deptname = value; }
            }
        }

    数据库部分:

     //作者:周丽同
        class DataAcess
        {
            private static readonly string db = "Sqlserver";//数据库名称,可以替换成Access;
            //private static readonly string db="Access";  
    
            public static IUser CreateUser()
            {
                IUser result = null;
                switch(db )//由于db的事先设置,所以此处可以根据选择实例化出相应的对象;
                {
                    case "Sqlserver":
                        result = new SqlserverUser();
                        break;
                    case "Access":
                        result =new AccessUser ();
                        break ;
                }
                return result ;
            }
    
            public static IDepartment  CreateDepartment()
            {
                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)
            {
                User user = new User();
                Department dept = new Department();
    
                IUser iu = DataAcess.CreateUser();//直接得到实际的数据库访问实例,而不存在任何依赖;
    
                iu.Insert(user);
                iu.GetUser(1);
    
                IDepartment id = DataAcess.CreateDepartment();
                id.Insert(dept);
                id.GetDepartment(1);
                Console.Read();
            }
    
        }

       上面的代码,很好的提高了复用性和后期维护性,贯彻了开——闭原则。但是如果下一个公司做网站要用Oracle数据库访问,那该怎么办?按着上面的代码思路只能改DataAccess类,在每个方法的switch中加case了。

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

       这里如果用到一个简单的.net技术就完美解决了。

    格式是:

    //Assembly.Load ("程序集名称".CreateInstance ("命名空间.类名称"))//只有在程序顶端协商using System.Reflection;来引用Reflection。
    有了反射,我们获得实例可以用下面两种写法:

    //常规写法
     //   IUser result=new SqlserverUser();
    
    //反射的写法
    //using System.Reflection;
    
    //    IUser result =(IUser)Assembly.Load("抽象工厂模式(当前程序的名称)").CreateInstance("抽象工厂模式(当前命名空间名称).SqlserverUser(要实例化的类名)");

    修改代码部分:

    //作者:周丽同
        class DataAccess
        {
            private static readonly string AssemblyName = "抽象工厂模式";
            private static readonly string db = "Sqlserver";//数据库名称,可替换成Access;
    
            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);
            }
        }

      比以前,代码是漂亮多了,但是在更换数据库访问时,还是需要去改程序(改db这个字符串的值)重编译,不完全符合真正的开放——封闭原则。反射+配置文件实现数据库访问程序可以解决更改DataAccess问题。

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

      我们可以通过读文件来给DB字符串赋值,在配置文件中写明是Sql Server还是Access,这样DataAccess类也不用更改了。

    添加一个App.config文件:

    //作者:周丽同
        <?xml version ="1.0" endcoding ="utf-8"?>
        <configuration>
            <appSetttings>
                <add key="DB" value="Sqlserver"/>//配置文件可以换成Access或者Oracle;
            </appSettings>
        <configuration>
      再添加引用 System.configuraiton,并在程序开头增加 using System.Configuration;,然后更改DataAccess类字段DB的赋值代码。

    #region
        private static readonly string db=ConfigurationManager.AppSettings["DB"];
    #endregion

    小结

      这样看来,其实在一些用到“switch~case或者If”的语句,都可以考虑用反射技术来解除分支判断带来的耦合。三大工厂模式,自认为,抽象工厂最为重要,而且里面的反射思想用的很棒!

    感谢您的宝贵时间~~~




  • 相关阅读:
    C++中整型变量的存储大小和范围
    A1038 Recover the Smallest Number (30 分)
    A1067 Sort with Swap(0, i) (25 分)
    A1037 Magic Coupon (25 分)
    A1033 To Fill or Not to Fill (25 分)
    A1070 Mooncake (25 分)
    js 获取控件
    C#代码对SQL数据库添加表或者视图
    JS 动态操作表格
    jQuery取得下拉框选择的文本与值
  • 原文地址:https://www.cnblogs.com/zhoulitong/p/6412442.html
Copyright © 2011-2022 走看看