系统架构技能之设计模式一、上篇回顾上篇我们主要讲述了简单工厂模式和工厂模式。并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下:简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建。工厂模式:多个工厂负责多个类型对象的创建,每个工厂只负责具体类型对象的创建,支持无缝的新增类型对象的创建,需要实现工厂接口类和具体的类型对象类。我们来简单的对比下这2个模式的优缺点:模式名称优点缺点简单工厂模式一个工厂负责所有对象的创建,简单灵活不符合高内聚的原则,不支持无缝的扩展工厂模式可以无缝的新增类型,每个工厂职责单一,符合高内聚的原则工厂类太多,难以维护。工厂模式,很优雅的解决了应用程序使用对象时的无限new()的操作,同时降低了系统应用之间的耦合性,提高了系统的可维护性和适应性。二、摘要本文主要是针对创建型模式中的抽象工厂模式进行讲述,抽象工厂模式是在简单工厂模式的基础上扩展而成的新模式,将简单工厂中的对象的创建过程进行了很优雅的动态配置来完成无缝的扩展,当然通过一些扩展,可以构建出可支持动态新增或者删除对象的抽象工厂模式。本文将会给出具体的实现方案,相比工厂模式,抽象工厂模式是一个工厂负责多个对象的创建,返回的具体的类型是这个对象的抽象类型。这样,在客户端引用的时候只需要使用这个工厂返回的对象类型,抽象工厂会自动根据对象的类型动态的创建这个类型对象的实例。大体的过程如下:上面的图片呢,主要是针对经典的抽象工厂模式给出了一个实现草图的模拟,而我们在实际的项目中可能并不希望给出这么多的抽象工厂工厂实现,我只想给出一个通用的抽象工厂实现,通过静态方法直接调用,返回我想要的对象类型的实例,而且这个对象类型是可以动态配置的,那么我们如何做到呢?这就是本篇需要讨论的实现方案。本篇将会从以下几点进行讲述抽象工厂模式:1、抽象工厂模式的简单实例代码-这里给出的是经典的抽象工厂模式实例代码。我们从经典的实例代码中可以看出这个工厂模式的一些缺点。2、根据经典工厂模式的缺点,我们给出改进的方案,进一步给出项目中可以使用的通用方案实现。3、给出上篇中的通过委托来实现的工厂模式方案。4、通过特性+反射的形式来动态的创建对象。三、本文大纲a、上篇回顾。b、摘要。c、本文大纲。d、抽象工厂模式的特点及使用场景。e、抽象工厂模式的实现方案。f、抽象工厂模式使用总结。g、系列进度。h、下篇预告。四、抽象工厂模式的特点及使用场景抽象工厂可以说是三类工厂模式中使用最广泛的,也是最受大家喜爱的模式之一,因为抽象工厂模式解决了一系列相互依赖的对象或者有组合关系的对象的创建过程。举个简单的例子来说,我们以电脑的显卡和风扇来说吧,我们知道显卡一般在玩游戏的时候,由于渲染图形会产生大量的热量,如果没有好的风扇那么可能无法达到好的散热的效果,这个时候我们可以把显卡和风扇的创建放在一个抽象工厂中进行创建,因为这2个对象是具有依赖关系的对象,那么我们来给出这个例子的完整实例代码:先看看2个对象类型的接口和抽象工厂的接口定义///<summary>///定义显卡抽象对象接口///</summary>publicinterfaceIDisplayCard{}///<summary>///定义显卡风扇抽象对象接口///</summary>publicinterfaceIDisplayFan{}///<summary>///定义显卡设备抽象工厂接口///</summary>publicinterfaceIAbstractDriveFactory{IDisplayCardCreateDisplayCard();IDisplayFanCreateDisplayFan();}我们来看看具体类型的实现和抽象工厂的具体实现。///<summary>///定义华硕显卡的具体对象///</summary>publicclassDisplayCardAsus:IDisplayCard{}///<summary>///华硕显卡配套风扇///</summary>publicclassDisplayFanAsus:IDisplayFan{}///<summary>///华硕显卡具体实现工厂///</summary>publicclassDriveFactoryAsus:IAbstractDriveFactory{IDisplayCardCreateDisplayCardAsus(){returnnewDisplayCardAsus();}IDisplayFanCreateDisplayFanAsus(){returnnewDisplayFanAsus();}}通过上面的代码,我们给出了抽象工厂的一个经典实例的实现方案,当然这不是我们开发中使用的实际形式,那么实际我们在项目中如何使用这个抽象工厂模式呢?我们一般是改进的方案去使用这个抽象工厂模式,我们如何改进呢?对于目前的,如果我不光创建显卡设备和配套的风扇设备,我还想创建其他的类型的东西,这时候可能我们定义的抽象工厂就无法满足具有相互依赖或者组合关系的对象类型实例的创建工作了,那么我们如何改进呢,这就是下面要讲述的几类方案。五、抽象工厂模式的实现方案5.1、通过配置文件来实现我们先给出基于上面的经典抽象工厂的一个改进的方案,可以支持动态配置的抽象工厂,一个工厂负责动态的创建一些列的可动态配置的对象列表,我们如何做呢,我想一提到配置。大家都知道要么是通过XML文件来实现或者是通过泛型集合来做。我们这里可以提供的方案是这样的,通过工厂初始化时从配置文件中读取配置项,构造一个字典,然后从这个字典中查询要创建的类型是否在字典中,如果在字典中存在则创建这个类型的对象,否则返回NULL,我们这里通过泛型来实现。我们来看看具体的代码实现吧:///<summary>///定义抽象工厂接口///</summary>publicinterfaceIAbstractFactory{///<summary>///通用的泛型对象创建工厂///</summary>///<typeparamname=T></typeparam>///<returns></returns>TCreate<T>();}给出具体的实现这个接口的抽象工厂类///<summary>///具体的通用工厂实现///</summary>publicclassAbstractFactory:IAbstractFactory{privatestaticreadonlyIDictionary<Type,Type>instances=null;publicstaticAbstractFactory(){//从具体的配置项中读取,从配置文件中读取或者通过某个方法来硬编码实现等。//这里推荐的做饭是从配置文件中读取。instances=newDictionary<Type,Type>();instances.Add(Type.GetType(),Type.GetType());instances.Add(Type.GetType(),Type.GetType());}publicTCreate<T>(){if(!instances.ContainsKey(typeof(T)))returndefault(T);TypetypeInstance=instances[typeof(T)];Tobj=(T)Activator.CreateInstance(typeInstance);returnobj;}}通过上面给出的代码,基本上可以满足一般项目的需求,大家当然有好的思路和建议也可以提出,给出更好的改进方案,下面我给出大概的配置文件格式,其实就是父子级节点,父级节点是负责创建的工厂类,那么这个父节点下的子节点就是工厂要创建的具体的对象类型。上图中描述的思路,我们大概知道了,对应这样的一个支持多个具有依赖关系或者组合关系的对象的动态抽象工厂的实现,那么如果我们想实现支持多个具有依赖关系或者组合关系的不同的创建形式的通用创建工厂时,我们如何来做呢?同上面的思路,只不过我们外部需要再添加一个字典,负责类型和抽象工厂的映射,即抽象工厂可以创建的字典列表及抽象工厂具体实例类型之间的键值对关系,或者通过配置文件来组织父子级的关系。我们大概的看下配置文件的组织吧:<?xmlversion=1.0encoding=utf-8?><AbstractFactory><FactorySections><FactorySectionname=ProductFactorytype=DesignPattern.ProductFactory><ObjectInstancename=type=/><ObjectInstancename=type=/><ObjectInstancename=type=/><ObjectInstancename=type=/></FactorySection><FactorySectionname=FoodFactorytype=DesignPattern.FoodFactory><ObjectInstancename=type=/><ObjectInstancename=type=/><ObjectInstancename=type=/><ObjectInstancename=type=/></FactorySection><FactorySectionname=BookFactorytype=DesignPattern.BookFactory><ObjectInstancename=type=/><ObjectInstancename=type=/><ObjectInstancename=type=/><ObjectInstancename=type=/></FactorySection></FactorySections></AbstractFactory>那么具体的抽象工厂的代码又如何组织呢?如下形式:///<summary>///具体的通用工厂实现///</summary>publicclassAbstractFactory:IAbstractFactory{///<summary>///工厂与工厂能够创建的对象类型字典之间的映射字典///</summary>privatestaticreadonlyIDictionary<Type,Dictionary<Type,Type>>typeMapper=null;privateTypefactoryType=null;publicstaticAbstractFactory(){//从具体的配置项中读取,从配置文件中读取或者通过某个方法来硬编码实现等。//这里推荐的做饭是从配置文件中读取。//根据配置文件中的ObjectInstance节点放在对应的工厂下的字典中//每个工厂节点FactorySection就会创建一个字典,并且将这个工厂能够创建的类型放在这个字典中typeMapper=newDictionary<Type,Dictionary<Type,Type>>();}publicAbstractFactory(stringtypeName){this.facto