抽象工厂模式(AbstractFactory)【创建型】

一、引言

     写了3篇有关设计模式的文章了,大家有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力。今天我要写第四个模式了,该模式叫抽象工厂。上一篇文章我们讲了【工厂方法】模式,它是为了解决【简单工厂】模式所面对的问题,它的问题就是:如果我们增加新的产品,工厂类的方法就要修改本身的代码,增加产品越多,其逻辑越复杂,同时这样的修改也是不符合【开放关闭原则OCP】,对修改代码关闭,对增加代码开放。为了解决【简单工厂】的问题,我们引出了【工厂方法】模式,通过子类化工厂类,解决了工厂类责任的划分,产品和相应的工厂一一对应,符合了OCP。如果我们要设计一套房子,当然我们知道房子是由房顶、地板、窗户、房门组成的,别的组件暂时省略,先设计一套古典风格的房子,再创建一套现代风格的房子,再创建一套欧式风格的房子,这么多套房子,我们该怎么办呢?今天我们要讲的【抽象工厂】模式可以很好的解决多套变化的问题。

二、抽象工厂详细介绍

  2.1、动机(Motivate):

     在软件系统中,经常面临着"一系统相互依赖的对象"的创建工作:同时,由于需求的变化,往往存在更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种"封装机制"来避免客户程序和这种"多系列具体对象创建工作"的紧耦合?

  2.2、意图(Intent):

    提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。                            ——《设计模式》GoF

  2.3、结构图(Structure)

    抽象工厂模式(AbstractFactory)【创建型】_第1张图片

   右上角AbstractFactory抽象类中的抽象方法 +CreateProductA(),+CreateProductB()对应了抽象类AbstractProductA,AbstractProductB

该图是抽象工厂的UML图,结合抽象工厂的意图、动机和图示来理解该模式,今天我们就以建设房子为例来说明抽象工厂的实现机理。

2.4、模式的组成

      可以看出,在抽象工厂模式的结构图有以下角色:

      (1)、抽象产品类角色(AbstractProduct):为抽象工厂中相互依赖的每种产品定义抽象接口对象,也可以这样说,有几种产品,就要声明几个抽象角色,每一个抽象产品角色和一种具体的产品相匹配。

      (2)、具体产品类(ConcreteProduct):具体产品类实现了抽象产品类,是针对某个具体产品的实现的类型。

      (3)、抽象工厂类角色(Abstract Factory):定义了创建一组相互依赖的产品对象的接口操作,每种操作和每种产品一一对应。

      (4)、具体工厂类角色(ConcreteFactory):实现抽象类里面的所有抽象接口操作,可以创建某系列具体的产品,这些具体的产品是“抽象产品类角色”的子类。


2.5、抽象工厂的具体代码实现

a

using System;
using System.Collections.Generic;
using System.Text;

namespace 抽象工厂模式
{

    abstract class shou
    {
    }

    abstract class shenzi
    {
        public abstract void add(shou a);
    }

    abstract class AbstractFactory //有几种产品,就要声明几个抽象角色,每一个抽象产品角色和一种具体的产品相匹配
    {
        public abstract shou shou();// 抽象产品
        public abstract shenzi shenzi();
    }

    class xiFactory : AbstractFactory
    {
        public override shou shou()
        {
            return new xishou();//具体的产品,纤细的手
        }
        public override shenzi shenzi()
        {
            return new xishenzi(); 
        }
    }

    class xishou : shou //具体产品
    {
    }

    class xishenzi : shenzi
    {
        public override void add(shou a)
        {
            Console.WriteLine(this.GetType().Name +
              " interacts with " + a.GetType().Name);
        }
    }

    class chuFactory : AbstractFactory
    {
        public override shou shou()
        {
            return new chushou();
        }
        public override shenzi shenzi()
        {
            return new chushenzi();
        }
    }

    class chushou : shou
    {
    }

    class chushenzi : shenzi
    {
        public override void add(shou a)
        {
            Console.WriteLine(this.GetType().Name +
              " interacts with " + a.GetType().Name);
        }
    }

    class Client
    {
        private shou shou;
        private shenzi shenzi;

        // Constructor 
        public Client(AbstractFactory factory) //预操作选择实现的工厂,是纤细的还是肥硕的
        {
            shou = factory.shou();
            shenzi = factory.shenzi();
        }

        public void Run() //实现抽象产品的抽象方法
        {
            shenzi.add(shou);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            AbstractFactory xifactory = new xiFactory();
            Client xiC = new Client(xifactory);
            xiC.Run();

            AbstractFactory chufactory = new chuFactory();
            Client chuC = new Client(chufactory);
            chuC.Run();

            Console.Read();

        }
    }
}

三、抽象工厂的实现要点

     1、如果没有应对“多系列对象创建”的需求变化,则没有必要使用AbstractFactory模式,这时候使用简单的静态工厂完全可以。

      2、"系列对象"指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中“道路”与“房屋”的依赖,“道路”与“地道”的依赖。

      3、AbstractFactory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。

      4、AbstractFactory模式经常喝FactoryMethod模式共同组合来应对“对象创建”的需求变化。

    3.1】、抽象工厂模式的优点:【抽象工厂】模式将系列产品的创建工作延迟到具体工厂的子类中,我们声明工厂类变量的时候是使用的抽象类型,同理,我们使用产品类型也是抽象类型,这样做就尽可能的可以减少客户端代码与具体产品类之间的依赖,从而降低了系统的耦合度。耦合度降低了,对于后期的维护和扩展就更有利,这也就是【抽象工厂】模式的优点所在。可能有人会说在Main方法里面(这里的代码就是客户端的使用方)还是会使用具体的工厂类,对的。这个其实我们通过Net的配置,把这部分移出去,最后把依赖关系放到配置文件中。如果有新的需求我们只需要修改配置文件,根本就不需要修改代码了,让客户代码更稳定。依赖关系肯定会存在,我们要做的就是降低依赖,想完全去除很难,也不现实。

   3.2】、抽象工厂模式的缺点:有优点肯定就有缺点,因为每种模式都有他的使用范围,或者说要解决的问题,不能解决的问题就是缺点了,其实也不能叫缺点了。【抽象工厂】模式很难支持增加新产品的变化,这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变,这样也就违背了“开发——封闭”原则。

   3.3】、抽象工厂模式的使用场景:   如果系统需要多套的代码解决方案,并且每套的代码方案中又有很多相互关联的产品类型,并且在系统中我们可以相互替换的使用一套产品的时候可以使用该模式,客户端不需要依赖具体实现。

 

五、总结

   终于写完了,写了3个小时,学习设计模式不能死学,要把握核心点和使用场景。关键点第一是,面向对象设计模式的基本原则,有了原则,考虑问题就不会跑偏,然后再仔细把握每种模式的使用场景和要解决的问题,多写写代码,多看看Net的类库,它是最好的教材。

天下国家,可均也;爵禄,可辞也;白刃,可蹈也;中庸不可能也

你可能感兴趣的:(设计模式)