zoukankan      html  css  js  c++  java
  • 设计模式之四(抽象工厂模式第三回合)

    前言

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

    抽象工厂模式最大的好处便是易于交换产品系列,由于具体工厂类,例如IFactory factory=new AccessFactory(),在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。我们的设计不能去防止需要的变更,那么我们的理想便是让改动变得最小,那么现在如果你要更改数据库访问,我们只需要更改具体工厂就可以做到。

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

    实际上,我们第二回合中的代码中,客户端所认识的只有IUser和IDepartment,至于它是用Sql Server来实现还是Access来实现就不知道了。

    但是接下来的问题是,如果我们再添加一个项目表Project,该怎么办?

    首先要增加三个类,IProject,SqlServerProject,AccessProject,还需要更改IFactory、以及SqlServerFactory和AccessFactory才可以实现。

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

    现在我们要对上面的关系代码进行整改,需要前面的简单工厂模式。http://www.cnblogs.com/aehyok/archive/2013/05/10/3072008.html

    public class DataAccess
    {
        private static readonly string  db="SqlServer";
        //private static readonly string db="Access";
    
        public static IUser CreateUser()
        {
            IUser result=null;
            switch(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;
        }
    }

    原先一个接口,两个接口的实现,现在我们用一个DataAccess类就可以来代替了。

    客户端调用方法也有所改动

    public class Test
    {
        public static void Main()
        {
            User user=new User();
            Console.WriteLine("调用开始");
            IUser iu=DataAccess.CreateUser();
            iu.Insert(user);
            iu.GetUser(1);
    
            Console.ReadLine();
        }
    }

    现在选择那个数据库是在DataAccess中定义的 private static readonly string  db="SqlServer";
    当然更好的办法实在配置文件中进行变动就可以了。

    如果如前言中所说 ,添加一个项目,那么我们只需要在DataAccess类中添加雷同的方法即可。

    但是还是有问题,前面我们也稍微提到过,比如现在有需求要用Oracle数据库。原来只需要增加OracleFactory工厂就可以了,现在就比较麻烦了。

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

     如果你还不太了解反射,那么可以简单的看一下我之前的一篇入门的反射博文http://www.cnblogs.com/aehyok/archive/2013/03/25/2963287.html

    首先使用反射我们需要引用using System.Reflection来引用Reflection,就可以使用反射来优化抽象工厂模式的先天不足。

    顺便来看一下反射的简单使用,来获得实例的方法

    IUser result = new SqlServerUser();   ///这是常规的写法

    接下来看看用反射的写法,别忘了首先要引用哦

    IUser result = (IUser)Assembly.Load("程序集的名称").CreateInstance("命名空间.要实例化的类名");

    那么现在可以发现用了反射我们可以利用字符串来实例化对象,而变量是可以替换的,而常规的写法都是写死在程序里的。
    接下来看看我们用反射优化后的抽象工厂,其实也就是对上面DataAccess类进行的优化。

        public class DataAccess
        {
            private static readonly string db = "SqlServer";
            private static readonly string AssemblyName = "AbstractFactory";
    
            public static IUser CreateUser()
            {
                string ClassName = AssemblyName+"."+db+"User";
                IUser result = (IUser)Assembly.Load("程序集的名称").CreateInstance("命名空间.要实例化的类名");
                return (IUser)Assembly.Load(AssemblyName).CreateInstance(ClassName);
            }
    
            public static IDepartment CreateDepartment()
            {
                string ClassName ="AssemblyName"+ "."+db+"Department";
                return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(ClassName);
            }
        }

    其实这里我们还可以简单的优化一下,就是用配置文件

    <?xml version="1.0"?>
    <configuration>
      <appSettings>
        <!--<add key="DB" value="SqlServer"/>-->
        <add key="DB" value="Access"/>
      </appSettings>
    <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
        public class DataAccess
        {
            private static readonly string db = ConfigurationManager.AppSettings["DB"];
            private static readonly string AssemblyName = "AbstractFactory";
    
            public static IUser CreateUser()
            {
                string ClassName = AssemblyName+"."+db+"User";
                IUser result = (IUser)Assembly.Load("程序集的名称").CreateInstance("命名空间.要实例化的类名");
                return (IUser)Assembly.Load(AssemblyName).CreateInstance(ClassName);
            }
    
            public static IDepartment CreateDepartment()
            {
                string ClassName ="AssemblyName"+ "."+db+"Department";
                return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(ClassName);
            }
    
        }

    这样需要什么数据库,只需要在配置文件当中进行配置即可。
    所以,所有在用简单工厂的地方,都可以考虑用反射来去除switch或if,接触分支判断带来的耦合。

    总结

     原来通过抽象工厂可以学到这么多的知识很好,要多多吸收才可以。

    最终版本的抽象工厂模式实例代码下载链接为http://url.cn/GgWA2K

  • 相关阅读:
    MOSS 2007(Designer) 自定义列表表单开发笔记1(表单字段控件格式化)
    不使用第三个变量,怎么交换两个变量的值?
    AT指令介绍
    转:iis 支持wap
    WAP传输协议
    计算生肖
    下载文件 转
    彩信MO,MT的业务流程(转)
    最详细AT指令
    WML标签手册
  • 原文地址:https://www.cnblogs.com/aehyok/p/3087777.html
Copyright © 2011-2022 走看看