zoukankan      html  css  js  c++  java
  • 系统架构技能之设计模式抽象工厂模式

    一、上篇回顾

            上篇我们主要讲述了简单工厂模式和工厂模式。并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下:

            简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建。

            工厂模式:多个工厂负责多个类型对象的创建,每个工厂只负责具体类型对象的创建,支持无缝的新增类型对象的创建,需要实现工厂接口类和具体的类型对象类。

            我们来简单的对比下这2个模式的优缺点:

    模式名称 优点 缺点
    简单工厂模式 一个工厂负责所有对象的创建,简单灵活 不符合高内聚的原则,不支持无缝的扩展
    工厂模式 可以无缝的新增类型,每个工厂职责单一,符合高内聚的原则 工厂类太多,难以维护。

            工厂模式,很优雅的解决了应用程序使用对象时的无限new()的操作,同时降低了系统应用之间的耦合性,提高了系统的可维护性和适应性。

    二、摘要

            本文主要是针对创建型模式中的抽象工厂模式进行讲述,抽象工厂模式是在简单工厂模式的基础上扩展而成的新模式,将简单工厂中的对象的创建过程进行了很优雅的动态配置来完成无

    缝的扩展,当然通过一些扩展,可以构建出可支持动态新增或者删除对象的抽象工厂模式。本文将会给出具体的实现方案,相比工厂模式,抽象工厂模式是一个工厂负责多个对象的创建,返回

    的具体的类型是这个对象的抽象类型。这样,在客户端引用的时候只需要使用这个工厂返回的对象类型,抽象工厂会自动根据对象的类型动态的创建这个类型对象的实例。大体的过程如下:

               image

    上面的图片呢,主要是针对经典的抽象工厂模式给出了一个实现草图的模拟,而我们在实际的项目中可能并不希望给出这么多的抽象工厂工厂实现,我只想给出一个通用的抽象

    工厂实现,通过静态方法直接调用,返回我想要的对象类型的实例,而且这个对象类型是可以动态配置的,那么我们如何做到呢?这就是本篇需要讨论的实现方案。本篇将会从

    以下几点进行讲述抽象工厂模式:

    1、抽象工厂模式的简单实例代码-这里给出的是经典的抽象工厂模式实例代码。我们从经典的实例代码中可以看出这个工厂模式的一些缺点。

              2、根据经典工厂模式的缺点,我们给出改进的方案,进一步给出项目中可以使用的通用方案实现。

              3、给出上篇中的通过委托来实现的工厂模式方案。

              4、通过特性+反射的形式来动态的创建对象。

    三、本文大纲

           a、上篇回顾。

           b、摘要。

           c、本文大纲。

           d、抽象工厂模式的特点及使用场景。

           e、抽象工厂模式的实现方案。

           f、抽象工厂模式使用总结。

           g、系列进度。

           h、下篇预告。

    四、抽象工厂模式的特点及使用场景

            抽象工厂可以说是三类工厂模式中使用最广泛的,也是最受大家喜爱的模式之一,因为抽象工厂模式解决了一系列相互依赖的对象或者有组合关系的对象的创建过程。举个简单的例子来

    说,我们以电脑的显卡和风扇来说吧,我们知道显卡一般在玩游戏的时候,由于渲染图形会产生大量的热量,如果没有好的风扇那么可能无法达到好的散热的效果,这个时候我们可以把显卡和

    风扇的创建放在一个抽象工厂中进行创建,因为这2个对象是具有依赖关系的对象,那么我们来给出这个例子的完整实例代码:

            先看看2个对象类型的接口和抽象工厂的接口定义

        /// <summary>
        /// 定义显卡抽象对象接口
        /// </summary>
        public interface IDisplayCard
        {
        }

        /// <summary>
        /// 定义显卡风扇抽象对象接口
        /// </summary>
        public interface IDisplayFan
        {
        }

        /// <summary>
        /// 定义显卡设备抽象工厂接口
        /// </summary>
        public  interface IAbstractDriveFactory
        {
            IDisplayCard CreateDisplayCard();

            IDisplayFan CreateDisplayFan();
        }

         我们来看看具体类型的实现和抽象工厂的具体实现。

        /// <summary>
        /// 定义华硕显卡的具体对象
        /// </summary>
        public class DisplayCardAsus : IDisplayCard
        {
        }

        /// <summary>
        /// 华硕显卡配套风扇
        /// </summary>
        public class DisplayFanAsus : IDisplayFan
        {
        }

        /// <summary>
        /// 华硕显卡具体实现工厂
        /// </summary>
        public class DriveFactoryAsus : IAbstractDriveFactory
        {
            IDisplayCard CreateDisplayCardAsus()
            {
                return new DisplayCardAsus();
            }

            IDisplayFan CreateDisplayFanAsus()
            {
                return new DisplayFanAsus();
            }
        }

            通过上面的代码,我们给出了抽象工厂的一个经典实例的实现方案,当然这不是我们开发中使用的实际形式,那么实际我们在项目中如何使用这个抽象工厂模式呢?我们一般是改进的方

    案去使用这个抽象工厂模式,我们如何改进呢?对于目前的,如果我不光创建显卡设备和配套的风扇设备,我还想创建其他的类型的东西,这时候可能我们定义的抽象工厂就无法满足具有相互

    依赖或者组合关系的对象类型实例的创建工作了,那么我们如何改进呢,这就是下面要讲述的几类方案。

    五、抽象工厂模式的实现方案

         5.1、通过配置文件来实现

    • 我们先给出基于上面的经典抽象工厂的一个改进的方案,可以支持动态配置的抽象工厂,一个工厂负责动态的创建一些列的可动态配置的对象列表,我们如何做呢,我想一提到配置。大家都知道要么是通过XML文件来实现或者是通过泛型集合来做。我们这里可以提供的方案是这样的,通过工厂初始化时从配置文件中读取配置项,构造一个字典,然后从这个字典中查询要创建的类型是否在字典中,如果在字典中存在则创建这个类型的对象,否则返回NULL,我们这里通过泛型来实现。
    • 我们来看看具体的代码实现吧:

        /// <summary>
        /// 定义抽象工厂接口
        /// </summary>
        public  interface IAbstractFactory
        {
            /// <summary>
            /// 通用的泛型对象创建工厂
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <returns></returns>
            T Create<T>();
        }

    给出具体的实现这个接口的抽象工厂类

       /// <summary>
       /// 具体的通用工厂实现
       /// </summary>
       public  class AbstractFactory : IAbstractFactory
       {
           private static readonly IDictionary<Type, Type> instances = null;

           public static AbstractFactory()
           {
               //从具体的配置项中读取,从配置文件中读取或者通过某个方法来硬编码实现等。
               //这里推荐的做饭是从配置文件中读取。
               instances = new Dictionary<Type, Type>();
               instances.Add(Type.GetType(""), Type.GetType(""));
               instances.Add(Type.GetType(""), Type.GetType(""));
           }
           public T Create<T>()
           {
               if (!instances.ContainsKey(typeof(T)))
                   return default(T);

               Type typeInstance = instances[typeof(T)];

               T obj = (T)Activator.CreateInstance(typeInstance);

               return obj;
           }
       }

    • 通过上面给出的代码,基本上可以满足一般项目的需求,大家当然有好的思路和建议也可以提出,给出更好的改进方案,下面我给出大概的配置文件格式,其实就是父子级节点,父级节点是负责创建的工厂
    • 类,那么这个父节点下的子节点就是工厂要创建的具体的对象类型。

    image

    上图中描述的思路,我们大概知道了,对应这样的一个支持多个具有依赖关系或者组合关系的对象的动态抽象工厂的实现,那么如果我们想实现支持多个具有依赖关系或者组合

    关系的不同的创建形式的通用创建工厂时,我们如何来做呢?同上面的思路,只不过我们外部需要再添加一个字典,负责类型和抽象工厂的映射,即抽象工厂可以创建的字典列

    表及抽象工厂具体实例类型之间的键值对关系,或者通过配置文件来组织父子级的关系。我们大概的看下配置文件的组织吧:

    <?xml version="1.0" encoding="utf-8" ?>
    <AbstractFactory>
        <FactorySections>
            <FactorySection name="ProductFactory" type="DesignPattern.ProductFactory">
                <ObjectInstance name="" type=""/>
                <ObjectInstance name="" type=""/>
                <ObjectInstance name="" type=""/>
                <ObjectInstance name="" type=""/>
            </FactorySection>
            <FactorySection name="FoodFactory" type="DesignPattern.FoodFactory">
                <ObjectInstance name="" type=""/>
                <ObjectInstance name="" type=""/>
                <ObjectInstance name="" type=""/>
                <ObjectInstance name="" type=""/>
            </FactorySection>
            <FactorySection name="BookFactory" type="DesignPattern.BookFactory">
                <ObjectInstance name="" type=""/>
                <ObjectInstance name="" type=""/>
                <ObjectInstance name="" type=""/>
                <ObjectInstance name="" type=""/>
            </FactorySection>
        </FactorySections>
    </AbstractFactory>

              那么具体的抽象工厂的代码又如何组织呢?如下形式:

        /// <summary>
        /// 具体的通用工厂实现
        /// </summary>
        public  class AbstractFactory : IAbstractFactory
        {
            /// <summary>
            /// 工厂与工厂能够创建的对象类型字典之间的映射字典
            /// </summary>
            private static readonly IDictionary<Type, Dictionary<Type, Type>> typeMapper = null;
            private Type factoryType = null;

            public static AbstractFactory()
            {
                //从具体的配置项中读取,从配置文件中读取或者通过某个方法来硬编码实现等。
                //这里推荐的做饭是从配置文件中读取。
                //根据配置文件中的ObjectInstance 节点放在对应的工厂下的字典中
                //每个工厂节点FactorySection 就会创建一个字典,并且将这个工厂能够创建的类型放在这个字典中
                typeMapper = new Dictionary<Type, Dictionary<Type, Type>>();
            }

            public  AbstractFactory(string typeName)
            {
                this.factoryType = Type.GetType(typeName);
            }
            public T Create<T>()
            {
                if(typeMapper.ContainsKey(this.factoryType))
                    return default(T);

                Dictionary<Type, Type> instances = typeMapper[this.factoryType];

                if (!instances.ContainsKey(typeof(T)))
                    return default(T);

                Type typeInstance = instances[typeof(T)];

                T obj = (T)Activator.CreateInstance(typeInstance);

                return obj;
            }
        }

    通过上面的代码我们就给出了一个通用的抽象工厂的可行的解决方案。

    5.2、通过委托来实现工厂模式

              我们先要定义一个委托:

    public delegate string DelegateFunctionHandler(string userName);

    基于这个委托的工厂实现方案

        /// <summary>
        /// 具体的通用工厂实现
        /// </summary>
        public  class DegelateFactory 
        {
            private DelegateFunctionHandler handler = null;

            public static  DelegateFunctionHandler Create()
            {
                if (handler == null)
                    handler = new DelegateFunctionHandler(this.Test);

                return handler;
            }

            public string Test(string name)
            {
                return "Test!";
            }

        }

               工厂返回一个委托类型的对象,当然我上面为了简单给出的test方法其实就是工厂内部的方法,当然这里还可以进行相应的改进,也可以通过配置文件来完成,通过配置文件把相应相

    应的委托事件方法,通过配置来通过工厂动态的创建。下面给出个思路吧,具体的实现我就不贴出来了:

    image也希望大家给出更好的实现思路和方案。希望能多多的交流。

    六、抽象工厂模式使用总结

             通过上面的实现方式和思路,我们来对比一下抽象工厂、工厂模式、简单工厂模式之间的差异和相同点。

             相同点

              1、都是为客户调用程序与具体的对象类型之间提供了一个解耦作用,这里怎么说呢?其实就是应用程序不关心这个对象是怎么出来的,只关系如何使用这个对象,而且以后就算对象发生变化,那么也不需

    要修改用户应用程序的代码。

             2、提高了程序的可维护性和低耦合性。

             异同点

             1、简单工厂模式:是简单的一些列没有任何依赖关系的对象的创建,内部包含复杂的逻辑关系,一半是通过配置或者参数来进行创建对象,适合对象类型不多,并且不会经常新增的情况下。

                   工厂模式:每个工厂负责具体类型对象的创建,提供了可以动态新增产品类型的创建,并不需要修改现有的程序就可以无缝的新增产品类型。

                   抽象工厂模式:支持动态的新增对象类型和新增工厂类型,实现多种依赖关系的对象或者组合关系的创建,适合现有项目中的对象创建过程。

             2、简单工厂模式:内部逻辑复杂,不符合高内聚的原则。

                   工厂模式:每次新增一个对象类型,就必须新增一个对应的创建工厂,无疑这是一个非常大的工作量。

                   抽象工厂模式:是在简单工厂模式的基础上经过改进具有前2个模式的优点,又屏蔽了他们的一些缺点。

    当然我们在具体的项目中,还是需要具体的情况具体分析,一般情况下,我们对于这种数据库平滑迁移时,简单工厂可能比其他2类工厂更容易做,也很灵活。

    七、系列进度。

          创建型

            1、系统架构技能之设计模式-单件模式

            2、系统架构技能之设计模式-工厂模式

            3、系统架构技能之设计模式-抽象工厂模式

            4、系统架构技能之设计模式-创建者模式

            5、系统架构技能之设计模式-原型模式

            结构型

            1、系统架构技能之设计模式-组合模式

            2、系统架构技能之设计模式-外观模式

            3、系统架构技能之设计模式-适配器模式

            4、系统架构技能之设计模式-桥模式

            5、系统架构技能之设计模式-装饰模式

            6、系统架构技能之设计模式-享元模式

            7、系统架构技能之设计模式-代理模式

            行为型

            1、系统架构技能之设计模式-命令模式

            2、系统架构技能之设计模式-观察者模式

            3、系统架构技能之设计模式-策略模式

            4、系统架构技能之设计模式-职责模式

            5、系统架构技能之设计模式-模板模式

            6、系统架构技能之设计模式-中介者模式

            7、系统架构技能之设计模式-解释器模式

    八、下篇预告。

           下篇将会针对创建者模式进行讲述,该模式也是创建型模式中最复杂的设计模式之一,该 模式是对一个对象的各个创建部分进行划分,最后创建出完整的对象,当然这里面的实现方式可以说还是

    那几类思路,我将会给出几个方案的关键代码,希望大家多提宝贵意见,错误之处还请指出,请大家继续支持。

  • CallHot

反馈文章质量,你可以通过快速通道评论:
查看全文
  • 相关阅读:
    hasCode in Java
    如何区分同一Class的不同实例对象
    如何构建XML文件
    Spring <context:property-placeholder/>的作用
    关于List的几个方法
    Java 中那些不常用的关键字
    设计模式
    Java源代码阅读-Object.toString()
    修复启动项
    centos关闭防火前
  • 原文地址:https://www.cnblogs.com/hegezhou_hot/p/1893388.html
  • Copyright © 2011-2022 走看看