一:抽象工厂模式:

抽象工厂模式提供一个创建产品的接口来负责创建相关或依赖的对象,而不具体明确指定具体类,抽象工厂允许客户使用抽象的接口来创建一组相关产品,而不需要知道或关心实际生产出的具体产品是什么。而在上次介绍工厂方法模式中我们介绍到,工厂方法模式可以克服简单工厂设计模式的难以扩展缺点,工厂方法模式中每个具体工厂中只完成单个实例的创建,因此具有很好的可扩展性。但是不论编程上还是现实中,一个工厂只创建单个实例或产品是不太合理的,这样子太浪费资源。我们的工厂应该是能创建一系列的产品,继续拿笔记本工厂为例子,一个联想笔记本的工厂,不可能只生产一个型号的联想笔记本,这样子,工厂方法模式就不适用了,但是抽象工厂模式就可以很好解决这个问题。

二、情景例子:

继续以笔记本工厂为例,联想笔记本发展到现在已经有很多的系列,一个系列里面还有很多分支型号,如果使用工厂方法模式,整个联想旗下每一款新型号就要建立一个的工厂,非常不合理。解决这个问题只需实现一个工厂能生产全部型号的联想笔记本,而因为各地的销售情况不一样,每个地方的生产比例不一样,使得各地的生产情况不同。下面来看看如何用抽象工厂模式实现这种情况。

三、相关代码:

1、先创建每个产品的抽象类:

    /// <summary>
    /// 联想15抽象类
    /// </summary>
    public abstract class Lenovo15
    {
        public abstract void SayHello();
    }
    /// <summary>
    /// 联想16抽象类
    /// </summary>
    public abstract class Lenovo16
    {
        public abstract void SayHello();
    }

2、实现不同地方不同型号生产数不一样:

    public class GuangZhouLenovo15 : Lenovo15
    {
        //广州生产联想15台数
        public override void SayHello()
        {
            Console.WriteLine("广州联想15生产300台");
        }
    }
    public class GuangZhouLenovo16 : Lenovo16
    {
        //广州生产联想16的台数
        public override void SayHello()
        {
            Console.WriteLine("广州联想16生产200台");
        }
    }
    public class ShangHaiLenovo15 : Lenovo15
    {
        //上海生产联想15台数
        public override void SayHello()
        {
            Console.WriteLine("上海联想15生产400台");
        }
    }
    public class ShangHaiLenovo16 : Lenovo16
    {
        //上海生产联想16的台数
        public override void SayHello()
        {
            Console.WriteLine("上海联想16生产100台");
        }
    }

3、创建抽象工厂类,提供一系列型号的生产接口:

    /// <summary>
    /// 抽象工厂类,提供创建每个产品的接口
    /// </summary>
    public abstract class AbstractFactory
    {
        public abstract Lenovo15 CreateLenovo15();
        public abstract Lenovo16 CreateLenovo16();
    }

4、各地工厂负责自己地区的不同型号笔记本生产工作:

    public class GuangZhouFactory : AbstractFactory
    {
        //广州生产联想15
        public override Lenovo15 CreateLenovo15()
        {
            return new GuangZhouLenovo15();
        }

        //广州生产联想16
        public override Lenovo16 CreateLenovo16()
        {
            return new GuangZhouLenovo16();
        }
    }
    public class ShangHaiFactory : AbstractFactory
    {
        //上海生产联想15
        public override Lenovo15 CreateLenovo15()
        {
            return new ShangHaiLenovo15();
        }

        //上海生产联想16
        public override Lenovo16 CreateLenovo16()
        {
            return new ShangHaiLenovo16();
        }
    }

6、调用

            //创建广州抽象工厂
            AbstractFactory guangzhouFactory = new GuangZhouFactory();
            //广州抽象工厂生产广州的联想15
            Lenovo15 guangzhoulenovo15 = guangzhouFactory.CreateLenovo15();
            guangzhoulenovo15.SayHello();
            Lenovo16 guangzhoulenovo16 = guangzhouFactory.CreateLenovo16();
            //广州抽象工厂生产广州的联想16
            guangzhoulenovo16.SayHello();

            //创建上海抽象工厂
            AbstractFactory shanghaiFactory = new ShangHaiFactory();
            //上海抽象工厂生产广州的联想15
            Lenovo15 shanghailenovo15 = shanghaiFactory.CreateLenovo15();
            shanghailenovo15.SayHello();
            Lenovo16 shanghailenovo16 = shanghaiFactory.CreateLenovo16();
            //上海抽象工厂生产广州的联想16
            shanghailenovo16.SayHello();

            Console.ReadKey();

7、扩展

如果联想公司想在深圳也开一家工厂,此时,只需要添加三个类:一个是深圳具体工厂类,负责创建深圳的联想15和联想16,另外两个类是具有深圳生产数量情况的联想15类和联想16类。从上面代码看出,抽象工厂对于系列产品的变化支持开放封闭原则,扩展起来非常简便,但是,抽象工厂对于添加新产品这种情况就不支持开放封闭原则,比如联想新出了一个型号联想17,这样就要去修改抽象工厂的接口,这也是抽象工厂的缺点所在。

四、总结:

优点:将具体产品的创建延迟到具体工厂的子类中,这样将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展

缺点:很难支持新种类产品的变化。这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变,这样也就违背了开发封闭原则。

使用抽象工厂模式的系统应该符合几个前提:

  • 一个系统不要求依赖产品类实例如何被创建、组合和表达的表达(所有工厂模式应用的前提)。
  • 这个系统有多个系列产品,而系统中只消费其中某一系列产品
  • 系统要求提供一个产品类的库,所有产品以同样的接口出现,客户端不需要依赖具体实现。