设计模式 - 抽象工厂模式

  在工厂方法模式中,我们使用一个工厂创建一个产品,也就是说一个具体的工厂对应一个具体的产品。但是有时候我们需要一个工厂能够提供多个产品对象,而不是单一的对象,这个时候我们就需要使用抽象工厂模式。

  在讲解抽象工厂模式之前,我们需要厘清两个概念
  
  产品等级结构产品的等级结构也就是产品的继承结构。例如一个为空调的抽象类,它有海尔空调、格力空调、美的空调等一系列的子类,那么这个抽象类空调和他的子类就构成了一个产品等级结构。

  产品族:产品族是在抽象工厂模式中的。在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。比如,海尔工厂生产海尔空调。海尔冰箱,那么海尔空调则位于空调产品族中。

  产品等级结构和产品族结构示意图如下:
这里写图片描述

1、基本定义

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂允许客户端使用抽象的接口来创建一组相关的产品,而不需要关系实际产出的具体产品是什么。这样一来,客户就可以从具体的产品中被解耦。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。

2、UML类图

这里写图片描述
在抽象工厂模式结构图中包含如下几个角色:
在抽象工厂模式结构图中包含如下几个角色:
● IFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
● Factory1/Factory2(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
● IProductA/IProductB(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
● ProductA1/ProductA2/ProductB1/ProductB2(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
在抽象工厂中声明了多个工厂方法,用于创建不同类型的产品,抽象工厂可以是接口,也可以是抽象类或者具体类

3、模式实现

我们就是现实中的例子来实现抽象工厂,海尔生产冰箱、洗衣机。美的也生产冰箱洗衣机,设计图如下:
这里写图片描述
代码实现
产品类代码如下:

 /// <summary>
    /// 冰箱
    /// </summary>
    public interface IFridge
    {
        void CreateFridge();
    }
    /// <summary>
    /// 海尔冰箱
    /// </summary>
     public class HaierFridge : IFridge
    {
        public void CreateFridge()
        {
            Console.WriteLine("生产了一台海尔冰箱");
        }
    }
    /// <summary>
    /// 美的冰箱
    /// </summary>
    public class MideaFridge:IFridge
    {
        public void CreateFridge()
        {
            Console.WriteLine("生产了一台美的冰箱");
        }
    }
    /// <summary>
    /// 洗衣机
    /// </summary>
    public interface IWasher
    {
        void CreateWasher();
    }
     /// <summary>
    /// 海尔洗衣机
    /// </summary>
   public class HaierWasher:IWasher
    {
        public void CreateWasher()
        {
            Console.WriteLine("生产了一台海尔洗衣机");
        }
    }
    /// <summary>
    /// 美的洗衣机
    /// </summary>
    public class MideaWasher:IWasher
    {
        public void CreateWasher()
        {
            Console.WriteLine("生产了一台美的洗衣机");
        }
    }

接下来我们来看工厂类,代码如下:

 /// <summary>
    /// 家用电器工厂类
    /// </summary>
    public interface IFactory
    {
        IFridge CreateFridgeInstance();
        IWasher CreateWasherInstance();
    }
    /// <summary>
    /// 海尔工厂类
    /// </summary>
    public class HaierFactory:IFactory
    {
        public IFridge CreateFridgeInstance()
        {
            return new HaierFridge();
        }
        public IWasher CreateWasherInstance()
        {
            return new HaierWasher();
        }
    }
    /// <summary>
    /// 美的工厂类
    /// </summary>
    public class MideaFactory:IFactory
    {
        public IFridge CreateFridgeInstance()
        {
            return new MideaFridge();
        }

        public IWasher CreateWasherInstance()
        {
            return new MideaWasher();
        }
    }

调用代码如下:

class Program
    {
        static void Main(string[] args)
        {
            IFactory factory = new HaierFactory();//调用海尔工厂类
            IFridge fridge = factory.CreateFridgeInstance();
            fridge.CreateFridge();//生产冰箱
            IWasher washer = factory.CreateWasherInstance();
            washer.CreateWasher();//生产洗衣机

            factory = new MideaFactory();//调用美的工厂类
            fridge = factory.CreateFridgeInstance();
            fridge.CreateFridge();//生产冰箱
            washer = factory.CreateWasherInstance();
            washer.CreateWasher();//生产洗衣机
        }
    }

4、“开闭原则”的倾斜性

在上面的示例中,我们可以较为方面的添加新工厂,如容声也生产冰箱与洗衣机,但是现在遇到一个非常严重的问题,就是如果我们想添加空调类时,发现原有系统居然不能够在符合“开闭原则”的前提下增加新的组件,原因是抽象工厂IFactory中根本没有提供创建空调实例的方法,如果需要增加空调,首先需要修改抽象工厂接口IFactory,在其中新增声明创建空调对象的方法,然后逐个修改具体工厂类,增加相应方法以实现不同的生产厂家都可以创建空调对象,此外还需要修改客户端,否则空调类无法应用于现有系统。
怎么办?答案是抽象工厂模式无法解决该问题,这也是抽象工厂模式最大的缺点。在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为“开闭原则”的倾斜性。“开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的,对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
(1) 增加产品族:对于增加新的产品族,抽象工厂模式很好地支持了“开闭原则”,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。
(2) 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了“开闭原则”。
正因为抽象工厂模式存在“开闭原则”的倾斜性,它以一种倾斜的方式来满足“开闭原则”,为增加新产品族提供方便,但不能为增加新产品结构提供这样的方便,因此要求设计人员在设计之初就能够全面考虑,不会在设计完成之后向系统中增加新的产品等级结构,也不会删除已有的产品等级结构,否则将会导致系统出现较大的修改,为后续维护工作带来诸多麻烦。
上面扩展容声容声代码,添加三个类、容声冰箱类,继承自冰箱接口;容声洗衣机类,继承自洗衣机里,容声工厂类,继承自工厂类(包含创建冰箱实例与洗衣机实例),代码如下:

 /// <summary>
    /// 容声冰箱
    /// </summary>
    public class RonShenFridge:IFridge
    {
        public void CreateFridge()
        {
            Console.WriteLine("生产了一台容声冰箱");
        }
    }
     /// <summary>
    /// 容声洗衣机
    /// </summary>
    public class RonShenWasher:IWasher
    {
        public void CreateWasher()
        {
            Console.WriteLine("生产了一台容声洗衣机");
        }
    }
     /// <summary>
    /// 容声工厂类
    /// </summary>
    public class RonShenFactory:IFactory
    {
        //创建冰箱实例
        public IFridge CreateFridgeInstance()
        {
            return new RonShenFridge();
        }
        //创建洗衣机实例
        public IWasher CreateWasherInstance()
        {
            return new RonShenWasher();
        }
    }

调用方法

 class Program
    {
        static void Main(string[] args)
        {
            IFactory factory = new HaierFactory();//调用海尔工厂类
            IFridge fridge = factory.CreateFridgeInstance();
            fridge.CreateFridge();//生产冰箱
            IWasher washer = factory.CreateWasherInstance();
            washer.CreateWasher();//生产洗衣机

            factory = new RonShenFactory();//调用容声工厂类
            fridge = factory.CreateFridgeInstance();
            fridge.CreateFridge();//生产冰箱
            washer = factory.CreateWasherInstance();
            washer.CreateWasher();//生产洗衣机
        }
    }

5、抽象工厂模式优缺点

抽象工厂模式的主要优点如下:

  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。

  • 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。

    抽象工厂模式的主要缺点如下:

  • 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。

    6、模式使用场景

    在以下情况下可以考虑使用抽象工厂模式:

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。

  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。

  • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如同一操作系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统的,此时具有一个共同的约束条件:操作系统的类型。

  • 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。

7、总结

  抽象工厂模式中主要的优点在于具体类的隔离,是的客户端不需要知道什么被创建了。其缺点在于增加新的等级产品结构比较复杂,需要修改接口及其所有子类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值