【设计模式】 抽象工厂模式 Abstract Factory Pattern

简单工厂模式是一个工厂类根据工厂方法的参数创建不出不同的产品, 工厂方法模式是每一个产品都有一个一一对应的工厂负责创建该产品。那么今天要讲的抽象工厂模式是一个工厂能够产生关联的一系列产品。抽象工厂模式相对于简单工厂和工厂方法模式来着更具抽象性。

一、抽象工厂模式演绎

我们先来看一个简单的需求: 甲方要开发一套办公自动化软件,其中有一个非常重要的功能就是要能够导入Word 文档和Excel 文档。

开发人员拿到需求后就开始编码了,  很快代码写完了:

public  class ImportTool
{
    public void ImportWord()
    {
        Console.WriteLine("Import Word");
    }

    public void ImportExcel()
    {
        Console.WriteLine("Import Excel");
    }
}

客户端调用代码:

class Program
{
    static void Main(string[] args)
    {
        ImportTool importTool = new ImportTool();
        importTool.ImportWord();
        importTool.ImportExcel();

        Console.ReadKey();
    }
}

输出结果:

看起来不错, 但是看代码,客户端的代码和具体的实现之间是直接new出来的 ,简直就是面向具体编程,没有接口没有抽象,是不是违背了ISP原则了?,那好开发人员决定提出一个抽象层,提出一个抽象的文档接口,   用简单工厂模式来实现这个需求:

UML 图如下:

代码如下:

public interface IDocument
{
    void Import();
}
public class WordDocument : IDocument
{
    public void Import()
    {
       Console.WriteLine("Import Word");
    }
}
public class ExcelDocument : IDocument
{
    public void Import()
    {
       Console.WriteLine("Import Excel");
    }
}

public class DocumentFactory
{
    public static IDocument Create(string documentType)
    {
        IDocument document;
        switch (documentType)
        {
            case "word":
                document = new WordDocument();
                break;
            case "excel":
                document = new ExcelDocument();
                break;
            default:
                throw new ArgumentException("Invalid argument: documentType");
        }

        return document;
    }
}

客户端调用:

static void Main(string[] args)
{
    IDocument document=DocumentFactory.Create("word");
    document.Import();

    document=DocumentFactory.Create("excel");
    document.Import();

    Console.ReadKey();
}

输出:

看起来完美这是一个标准的静态工厂模式的实现。

第一次需求变更: 增加 对Power Point 的导入支持

增加了一个产品相当于,因为之前应用了简单工厂模式现在改起来很简单。

UML 图:

代码:

public interface IDocument
{
    void Import();
}
public class WordDocument : IDocument
{
    public void Import()
    {
 	        Console.WriteLine("Import Word");
    }
}
public class ExcelDocument : IDocument
{
        public void Import()
    {
 	    Console.WriteLine("Import Excel");
    }
}
public class PowerPointDocument : IDocument
{
    public void Import()
    {
        Console.WriteLine("Import Power Point");
    }
}

public class DocumentFactory
{
    public static IDocument Create(string documentType)
    {
        IDocument document;
        switch (documentType)
        {
            case "word":
                document = new WordDocument();
                break;
            case "excel":
                document = new ExcelDocument();
                break;
            case "powerpoint":
                document = new PowerPointDocument();
                break;
            default:
                throw new ArgumentException("Invalid argument: documentType");
        }

        return document;
    }
}

客户端调用:

static void Main(string[] args)
{
    IDocument document=DocumentFactory.Create("word");
    document.Import();

    document=DocumentFactory.Create("excel");
    document.Import();

    document = DocumentFactory.Create("powerpoint");
    document.Import();
    Console.ReadKey();
}

输出结果:

没问题,一起都在控制之中。

第二次需求变更: 支持office 2007 以后的文档格式。

Offcie 2007是个坎,2007之前的文档格式和2007以后的文档格式不一 样, word 在2007前的文档后缀是.doc, 2007 及以后就变成.docx了这个看似简单的需求实则是增加了小一半的工作量啊,新的格式的文档要重新进行解码才能拿到正确的数据,拿刚刚实现的简单工厂设计模式来应对这次变更就要新增加3个产品类并且要工厂来创建创建者三个类的实例。看来静态工厂已经不能再适应这一次的需求变化了,会导致静态工厂方法的逻辑变得异常复杂难以维护。那用工厂方法模式来解决这个问题,工厂方法刚好可以将产品的创建工作提取到单独的工厂中去完成,重构下工厂将静态工厂模式替换成工厂方法模式:

UML 图:

代码:

public interface IDocument
{
    void Import();
}
public interface IDocumentFactory
{
    IDocument Create();
}
public class WordDocument : IDocument
{
    public void Import()
    {
 	        Console.WriteLine("Import Word");
    }
}
public class ExcelDocument : IDocument
{
        public void Import()
    {
 	    Console.WriteLine("Import Excel");
    }
}
public class PowerPointDocument : IDocument
{
    public void Import()
    {
        Console.WriteLine("Import Power Point");
    }
}

public class WordXDocument : IDocument
{
    public void Import()
    {
        Console.WriteLine("Import WordX");
    }
}
public class ExcelXDocument : IDocument
{
    public void Import()
    {
        Console.WriteLine("Import ExcelX");
    }
}
public class PowerPointXDocument : IDocument
{
    public void Import()
    {
        Console.WriteLine("Import Power PointX");
    }
}

public class WordDocumentFactory : IDocumentFactory
{
    public  IDocument Create()
    {
        return new WordDocument();
    }
}
public class WordXDocumentFactory : IDocumentFactory
{
    public IDocument Create()
    {
        return new WordXDocument();
    }
}

public class ExcelDocumentFactory : IDocumentFactory
{
    public IDocument Create()
    {
        return new ExcelDocument();
    }
}
public class ExcelXDocumentFactory : IDocumentFactory
{
    public IDocument Create()
    {
        return new ExcelXDocument();
    }
}
public class PowerPointDocumentFactory : IDocumentFactory
{
    public IDocument Create()
    {
        return new PowerPointDocument();
    }
}
public class PowerPointXDocumentFactory : IDocumentFactory
{
    public IDocument Create()
    {
        return new PowerPointXDocument();
    }
}

客户端调用代码:

static void Main(string[] args)
{
    IDocument document;
    IDocumentFactory documentFactory;

    documentFactory = new WordDocumentFactory();
    document = documentFactory.Create();
    document.Import();

    documentFactory = new WordXDocumentFactory();
    document = documentFactory.Create();
    document.Import();

    documentFactory = new ExcelDocumentFactory();
    document = documentFactory.Create();
    document.Import();

    documentFactory = new ExcelXDocumentFactory();
    document = documentFactory.Create();
    document.Import();

    documentFactory = new PowerPointDocumentFactory();
    document = documentFactory.Create();
    document.Import();

    documentFactory = new PowerPointXDocumentFactory();
    document = documentFactory.Create();
    document.Import();

    Console.ReadKey();
}

输出结果:

一个产品一个实现类,一个工厂类,这样职责单一符合SRP,但是系统中的类在成倍的增加,有点复杂了,如果在增加一个系列的产品那还了得。

那么能不能减少一些类呢?经过分析我们发现,这些导入的文档中2007之前的一系列文档的解析规则基本类似实现的技术也是类似的,2007及以后的文档的解析规则类似。所以我们可以把这些产品分成两个系列,2007之前的成为Document系列,2007以后的文档成为DocumentX系列, 那么我们就可以创建两个具体的工厂来创建Document系列和DocumentX系列, 从另一个维度来看,Word 和WordX, Excel 和ExcelX,PowerPoint 和 PowerPointX的的关系也很密切,因为都是同一个产品,只是处在不同的系列上,他们各自的编码又各自类似,因此在这个维度上可以将其提出一组新的接口,IWordDocument 用于处理word的导入(Word和WordX),IExcelDocument 用处理Excel的导入(Excel 和ExcelX),IPowerPoint用于处理 PowerPoint 导入(PowerPoint和PowerPointX),根据这个思路重构代码:

UML 图

代码:

public interface IWordDocument
{
    void Import();
}
public interface IExcelDocument
{
    void Import();
}
public interface IPowerPointDocument
{
    void Import();
}
public interface IDocumentFactory
{
    IWordDocument CreateWord();
    IExcelDocument CreateExcel();
    IPowerPointDocument CreatePowerPoint();
}
public class WordDocument : IWordDocument
{
    public void Import()
    {
 	        Console.WriteLine("Import Word");
    }
}
public class WordXDocument : IWordDocument
{
    public void Import()
    {
        Console.WriteLine("Import WordX");
    }
}
public class ExcelDocument : IExcelDocument
{
    public void Import()
    {
 	    Console.WriteLine("Import Excel");
    }
}
public class ExcelXDocument : IExcelDocument
{
    public void Import()
    {
        Console.WriteLine("Import ExcelX");
    }
}
public class PowerPointDocument : IPowerPointDocument
{
    public void Import()
    {
        Console.WriteLine("Import Power Point");
    }
}
public class PowerPointXDocument : IPowerPointDocument
{
    public void Import()
    {
        Console.WriteLine("Import Power PointX");
    }
}
public class DocumentFactory : IDocumentFactory
{
    public IWordDocument CreateWord()
    {
        return new WordDocument();
    }

    public IExcelDocument CreateExcel()
    {
        return new ExcelDocument();
    }

    public IPowerPointDocument CreatePowerPoint()
    {
        return new PowerPointDocument();
    }
}
public class DocumentXFactory : IDocumentFactory
{
    public IWordDocument CreateWord()
    {
        return new WordXDocument();
    }

    public IExcelDocument CreateExcel()
    {
        return new ExcelXDocument();
    }

    public IPowerPointDocument CreatePowerPoint()
    {
        return new PowerPointXDocument();
    }
}

客户端调用:

static void Main(string[] args)
{
    IWordDocument wordDocument;
    IExcelDocument excelDocument;
    IPowerPointDocument powerPointDocument;

    IDocumentFactory documentFactory;

    documentFactory = new DocumentFactory();
    wordDocument = documentFactory.CreateWord();
    excelDocument = documentFactory.CreateExcel();
    powerPointDocument = documentFactory.CreatePowerPoint();
    wordDocument.Import();
    excelDocument.Import();
    powerPointDocument.Import();

    documentFactory = new DocumentXFactory();
    wordDocument = documentFactory.CreateWord();
    excelDocument = documentFactory.CreateExcel();
    powerPointDocument = documentFactory.CreatePowerPoint();
    wordDocument.Import();
    excelDocument.Import();
    powerPointDocument.Import();    

    Console.ReadKey();
}

输出:

这一次工厂的数量得到了控制,这里只有两个工厂类就搞定了,DocumentFactory 负责创建office 2007之前的文档对象,DocumentXFactory 负责创建 office 2007以及以后的文档对象。这就解决了工厂方法模式工厂类随着产品增加随之增加带来的复杂性,以及不易维护的问题。这样如果在增加一系列产品就变得容易了很多,只需要再创建一个系列产品的具体工厂并继承自抽象工厂,以及实现系列产品的抽象接口的具体类就可以了。

随着需求的变化一步一步的经过重构代码也一步一步从简单工厂模式到工厂方法模式再到抽象工厂模式了。现在文档处理代码就是一个典型的抽象工厂模式了,那么下面来看看抽象工厂模式到底是什么?

二、抽象工厂模式定义:

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的产品,这些产品构成了一个产品族(产品系列).

三、工厂方法模式结构图:

抽象工厂模式结构图

1、AbsctactFactory(抽象抽象工厂):

它声明了一组用于创建一系列产品的方法,每一个方法对应创建一种产品。

2.ConcreteFactory(具体工厂):

它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品系列,每个产品都在同一个系列中。

3. AbsctactProdcut(抽象产品):

它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。

4.ConcreteProdcut(具体产品):

它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。

四、抽象工厂模式代码实现

在抽象工厂中声明了多个工厂方法,用于创建不同类型的产品,抽象工厂可以是接口,也可以是抽象类或者具体类,其典型代码如下:

public interface IAbstractProdcutA
{
    void DoSomething();
}
public interface IAbstractProdcutB
{
    void DoSomething();
}
public interface IAbstractFactory{
    IAbstractProdcutA CreateProductA();
    IAbstractProdcutB CreateProductB();
}

public class ConcreteProductA1:IAbstractProdcutA
{
    public void DoSomething()
    {
 	    Console.WriteLine("I‘m ConcreteProductA1");
    }
}
public class ConcreteProductA2:IAbstractProdcutA
{
    public void DoSomething()
    {
 	    Console.WriteLine("I‘m ConcreteProductA2");
    }
}

public class ConcreteProductB1:IAbstractProdcutB
{
    public void DoSomething()
    {
 	    Console.WriteLine("I‘m ConcreteProductB1");
    }
}
public class ConcreteProductB2:IAbstractProdcutB
{
    public void DoSomething()
    {
 	    Console.WriteLine("I‘m ConcreteProductB2");
    }
}

public class ConcreteFactory1 : IAbstractFactory
{
    public IAbstractProdcutA CreateProductA()
    {
        return new ConcreteProductA1();
    }
    public IAbstractProdcutB CreateProductB()
    {
        return new ConcreteProductB1();
    }
}

public class ConcreteFactory2 : IAbstractFactory
{
    public IAbstractProdcutA CreateProductA()
    {
        return new ConcreteProductA2();
    }
    public IAbstractProdcutB CreateProductB()
    {
        return new ConcreteProductB2();
    }
}

客户端调用代码:

static void Main(string[] args)
{
    IAbstractProdcutA productA;
    IAbstractProdcutB productB;

    IAbstractFactory factory = new ConcreteFactory1();
    productA = factory.CreateProductA();
    productB = factory.CreateProductB();
    productA.DoSomething();
    productB.DoSomething();

    factory = new ConcreteFactory2();
    productA = factory.CreateProductA();
    productB = factory.CreateProductB() ;
    productA.DoSomething();
    productB.DoSomething();

    Console.ReadKey();
}

输出:

五 、抽象工厂模式的优点

  1. 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。比如常用的配置+反射就可轻松替换掉工厂进而替换掉整个以为逻辑。
  2. 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品系列中的对象。
  3. 增加新的产品系列很方便,无须修改已有系统,只需要增加具体产品类和具体工厂就可以了符合“开闭原则(OCP)“。

六、抽象工厂模式的缺点

  1. 增加新的产品麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则(OCP)“。如果新增一个产品就要在抽象工厂中增加一个创建该产品的方法。这样就牵一发动全身,原来的所有集成该抽象工厂的具体工厂都要修改。

七、抽象工厂模式的使用场景

  1. 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。
  2. 系统中有多于一个的产品系列,而每次只使用其中某一产品系列。可以通过配置文件等方式来使得用户可以动态改变产品系列,也可以很方便地增加新的产品系列。
  3. 属于同一个产品系列的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个产品系列中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如Office 文档的支持,在window xp  重视不能使用Office 2007 +的,window 7 支持0ffice 2007,因此这个约束就是操作系统对office版本的支持。
  4. 产品类型稳定,设计完成之后,不会向系统中增加新的产品类型或者删除已有的产品产品类型。

八、扩展

第三次需求改变:从商业化上考虑甲方要求这个软件的某些版本只提供导入office 2007 之前的文件,某些版本只支持2007以后版本。

怎么办呢? 这个需求开发人员拿到后一定窃喜,抽象工厂实现这种需求简直是太容易了。配置+反射呀, 将具体工厂配置在配置文件中,代码中只是用抽象并通过反射来创建工厂实进而达到动态控制的能力。

如果软件版本中V1中只要支持office 2007以前的文档版本。那么在配置文件App.config  增加以下节点:

配置完节点后在代码中通过反射来创建工厂类, 代码如下

static void Main(string[] args)
{
    IWordDocument wordDocument;
    IExcelDocument excelDocument;
    IPowerPointDocument powerPointDocument;

    IDocumentFactory documentFactory;

    // 读取配置文件并且通过反射创建工厂实例
    var setting = ConfigurationSettings.AppSettings["DocumentFaccory"];
    var obj = Type.GetType(setting);
    if (obj == null) return;
    documentFactory = Activator.CreateInstance(obj) as IDocumentFactory;

    if (documentFactory == null) return;

    wordDocument = documentFactory.CreateWord();
    excelDocument = documentFactory.CreateExcel();
    powerPointDocument = documentFactory.CreatePowerPoint();
    wordDocument.Import();
    excelDocument.Import();
    powerPointDocument.Import();

    Console.ReadKey();
}

输出结果如下:

如果在V1.1版本中甲方提出要求只支持office 2007以后的版本,那么只需要修改配置文件如下就可以了:

把原来的

<appSettings>
    <add key="DocumentFaccory" value="DesignPattern.AbstractFactory.DocumentFactory"/>
</appSettings>

改成:

<appSettings>
    <add key="DocumentFaccory" value="DesignPattern.AbstractFactory.DocumentXFactory"/>
</appSettings>

其它地方不用做任何修改,输出结果:

原文地址:https://www.cnblogs.com/vaiyanzi/p/9388665.html

时间: 2024-10-12 15:43:47

【设计模式】 抽象工厂模式 Abstract Factory Pattern的相关文章

设计模式 - 抽象工厂模式(abstract factory pattern) 详解

抽象工厂模式(abstract factory pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/27091671 参考工厂模式: http://blog.csdn.net/caroline_wendy/article/details/27081511 抽象工厂模式: 提供一个接口, 用于创建相关或依赖对象的家族, 而不需要明确指定具体类. 全部代码: http://download.csdn.net/de

设计模式 - 抽象工厂模式(abstract factory pattern) 具体解释

抽象工厂模式(abstract factory pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/27091671 參考工厂模式: http://blog.csdn.net/caroline_wendy/article/details/27081511 抽象工厂模式: 提供一个接口, 用于创建相关或依赖对象的家族, 而不须要明白指定详细类. 所有代码: http://download.csdn.net/

二十四种设计模式:抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式(Abstract Factory Pattern) 介绍提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 示例有Message和MessageModel,Message有一个Insert()方法,该方法的参数是MessageModel. AbstractMessageModel using System; using System.Collections.Generic; using System.Text; namespace Pattern.Abstract

Android设计模式——抽象工厂模式(Abstract Factory)

二十三种设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模式,共十一种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 1 package com.example.main; 2 3 import android.app.Activity; 4 import

php设计模式——抽象工厂模式(Abstract Factory)

二十三种设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模式,共十一种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 1 <?php 2 /* 3 * php设计模式——抽象工厂模式(Abstract Factory) 4 */ 5 6 7 /* 8 * I

设计模式-04抽象工厂模式(Abstract Factory Pattern)

1.模式动机 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法.但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象. 为了更清晰地理解工厂方法模式,需要先引入两个概念: 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机.海信电视机.TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌

Objective-C设计模式——抽象工厂模式Abstract Factory(对象创建)

抽象工厂模式 理解了工厂方法模式,其实抽象工厂和工厂方法模式有很多的相似之处.抽象工厂同样是分离客户端对象的创建和逻辑代码的,但是抽象工厂往往是产生一组数据而不单单是产生一个产品. 抽象工厂提供一个创建一系列相关或相互依赖对象接口,而无需制定它们具体的类. 抽象工厂与工厂方法 抽象工厂 通过对象组合创建抽象产品 创建多系列产品 必须修改父类的接口才能支持新的产品 工厂方法 通过类继承创建抽象产品 创建一种产品 子泪花创建者并重载工厂方法以创建新产品 Demo 比较多就不一一的贴代码了,截类图 客

抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式概述 定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类 抽象工厂抽象工厂,顾名思义,就是比工厂模式更抽象的工厂模式.在工厂模式中,一个具体工厂只负责生产一个具体产品.而在抽象工厂模式中,一个具体工厂可以生产一组相关的产品,这些产品称为产品族,产品族中的每一个产品部分属于每一个产品继承等级结构 首先我们先了解下什么是产品族和产品等级结构.产品等级结构即产品的继承结构,好比一个抽象类是汽车,其子类包括奔驰,宝马,大众,保时捷.....这样抽象汽车与具体汽车品牌之间

抽象工厂模式(abstarct factory pattern)和工厂模式(factory pattern)的比较

抽象工厂模式和工厂模式从字面上来看就有必然的联系,他们都是创建型模式.总结来说,工厂模式(factory pattern)只是个小工厂,只提供一层接口的实现类的输出,而抽象工厂模式(abstract factory pattern)是工厂模式的进一步升级,可以上升到两层以上的工厂模式继承,是工厂的工厂.一计算机来说,工厂模式可以是不同型号显示器,CPU或者网卡的提供者,而抽象工厂模式是显示器工厂.CPU工厂和网卡工厂的工厂.可以通过抽象工厂来获得CPU工厂,进而获得某个型号的CPU.整个依赖关系