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

来源:互联网 发布:淘宝钻位展示 编辑:程序博客网 时间:2024/05/18 04:47

前言

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

内容

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

背景

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

感谢您的宝贵时间~~~




0 1