• 设计模式——抽象工厂之反射“+”


    前言

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

    内容

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

    背景

      给一家企业做的电子商务网站,使用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”的语句,都可以考虑用反射技术来解除分支判断带来的耦合。三大工厂模式,自认为,抽象工厂最为重要,而且里面的反射思想用的很棒!

    感谢您的宝贵时间~~~




  • 相关阅读:
    [CareerCup] 4.6 Find Next Node in a BST 寻找二叉搜索树中下一个节点
    Android 接入支付宝支付实现
    Android 设置软键盘搜索键以及监听搜索键点击事件
    Android 应用监听自身卸载,弹出用户反馈调查
    ndk制作so库,ndk-build不是内部或外部命令。。。的错误
    Error: Your project contains C++ files but it is not using a supported native build system
    Android开发之——依赖冲突Program type already present
    基于Python的开源人脸识别库:离线识别率高达99.38%
    Android5.0以后,materialDesign风格的加阴影和裁剪效果
    Android 5.0 以上监听网络变化
  • 原文地址:https://www.cnblogs.com/zhoulitong/p/6412442.html
Copyright © 2020-2023  润新知