zoukankan      html  css  js  c++  java
  • 设计模式之抽象工厂

    工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。

    简单工厂 VS 抽象工厂:关于这两个模式的区别,我思考了下。简单工厂只所以简单,是因为它只是把创建一个类的过程进行了封装(这些类一般来说有一个公共的基类),通过Switch或者其他的判断形式创建需要的类(当然也是可以使用反射);而抽象工厂创建的类更为复杂,通常来说创建的类(子类)有同一基类,而在不同情形下选择对应的子类。

    情形重现:

    说到抽象工厂,必定想到对于不同数据库怎么快速切换类对象,也就是说可以很方便简单创建自己想到的类对象,废话不多说。

    实体类接口:

        interface IUser
        {
             void Add(IUser user);
             List<IUser> GetUsers();
        }

    一个IUser类型的接口,作为所有User类型的接口(不管是SqlServer还是Oracle或者Access)。

    实现类:

    SqlServer:

        class SqlServerUser:IUser
        {
            public void Add(IUser user)
            {
               
            }
    
            public List<IUser> GetUsers()
            {
                return new List<IUser>();
            }
        }

    Oracle:

        class OracleUser:IUser
        {
            public void Add(IUser user)
            {
    
            }
    
            public List<IUser> GetUsers()
            {
                return new List<IUser>();
            }
        }

    根据模式的定义,会有一个工厂的接口,以及工厂的子类,如下:

    工厂接口:

        interface IDataFactory
        {
            IUser CreateUser();
        }

    SqlServer工厂:

        class SqlServerDataFactory:IDataFactory
        {
            public IUser CreateUser()
            {
                return new SqlServerUser();
            }
        }

    Oracle工厂:

        class OracleDataFactory:IDataFactory
        {
            public IUser CreateUser()
            {
                return new  OracleUser();
            }
        }

    代码的过程还是比较简单,创建实体类接口,创建接口的实现类(具体实现类有几个根据自己的需要);创建工厂的接口,创建工厂的实现类(具体实现类有几个同样根据自己的需要),在实现类中将工厂的方法进行完善(创建对应的实体类型)。

    使用喽:

                IDataFactory sqlDataFactory = new SqlServerDataFactory();
                IDataFactory oracleDataFactory = new OracleDataFactory();
                IUser sqlUser = sqlDataFactory.CreateUser();
                IUser oracleUser = oracleDataFactory.CreateUser();

    创建对应的工厂类(SqlServer或者Oracle),使用工厂类创建对应的实体(SqlServer或者Oracle)。

    当然,我们的数据库中,肯定不止一张User表,可能还有Role表或者是RoleAndUser等等很多张表,这样的话我们就要创建对应类的接口和接口的对应实现类,同时还要修改工厂的接口(添加对应的创建实体方法),还有工厂接口的实现类不能忘了哦。好复杂,好繁琐。

    终极武器:

    刚才已经分析了,如果增加了一个类或者删除了一个类,需要修改四个地方,所以我们拿出杀手锏"反射"。

    第一步,先来个大裁员,删掉工厂(工厂和工厂的接口都不要);

    第二步,添加一个操作工厂(其实就是一个类,放了之前抽象工厂中的方法);

    第三步,添加两个变量,一个代表实体类的程序集,一个代表当前创建哪个类型的实体(SqlServer还是Oracle)。

    如下所示:

        class DataFactory
        {
            private static readonly string AssemblyName = "程序集(或者包含命名空间)";
            private static readonly string db = "SqlServer";
            public static IUser CreateUser()
            {
                string typeName = AssemblyName + "." + db + "." + db + "User";
                return (IUser)Assembly.Load(AssemblyName).CreateInstance(typeName);
            }
        }

    其实AssemblyName是否包含命名空间自己可以决定,当前的实没有包含的,当然如果包含了就无法使用Assembly.Load了哦。

    代码修改之后,如果我们要增加其他的实体类,只需增加一个类的接口和匹配的实现类即可。细心的你会发现,这样如果要创建Oracle会很麻烦,因为要修改db的值,这一点可以通过配置的方式进行实现,只需动态读取配置文件即可,但是感觉这样还是有一点不太好的,毕竟在程序的运行中我们可能随时访问任意一个类型的,所以这一点来说我们的第一种方式就没有这种问题。在这里我倒是推荐大家可以适当修改下创建方法,可以给其添加一个参数,用于决定创建哪个类型,当然最好是一个常量,或者是一个私有的全局变量,甚至是一个枚举也都是ok的,关键看大家个人的喜好了。

    好了,这次的抽象工厂就说这么多,希望大家多提意见和建议,代码在这里下载

  • 相关阅读:
    初中生数学题
    防御准备
    约数个数和「SDOI2015」
    暑期集训题目
    【模板】可持久化线段树 1(主席树)
    【模板】可持久化数组(可持久化线段树/平衡树)
    权值线段树&&线段树合并
    回家的路「SHOI 2012」
    Function「ZJOI2009」
    主席树-可持久化线段树学习笔记
  • 原文地址:https://www.cnblogs.com/ListenFly/p/3220142.html
Copyright © 2011-2022 走看看