zoukankan      html  css  js  c++  java
  • 设计模式(六)抽象工厂模式

    一、应用背景

      还是以宝马汽车制造为例。

      随着客户的要求越来越高,宝马车需要不同配置的空调和发动机等配件。于是这个工厂开始生产空调和发动机,用来组装汽车。这时候工厂有两个系列的产品:空调和发动机。宝马320系列配置A型号空调和A型号发动机,宝马230系列配置B型号空调和B型号发动机。

    二、具体例子:

      抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。比如宝马320系列使用空调型号A和发动机型号A,而宝马230系列使用空调型号B和发动机型号B,那么使用抽象工厂模式,在为320系列生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件型号A。 

    三、代码实践

      1 /*
      2 @author CodingMengmeng
      3 @datetime:2016-9-30 10:26:46
      4 @description:Abstract Factory Pattern.
      5 */
      6 #include <iostream>
      7 #include <tchar.h>
      8 using namespace std;
      9 //Engine
     10 class CEngine{
     11 public:
     12     CEngine()
     13     {
     14     }
     15     ~CEngine()
     16     {
     17     }
     18     virtual void getStyleOfEngine(void) = 0;
     19 };
     20 //type A of Engine
     21 class CEngineA :public CEngine{
     22 public:
     23     CEngineA()
     24     {
     25     }
     26     ~CEngineA()
     27     {
     28     }
     29 
     30     void getStyleOfEngine()
     31     {
     32         cout << "Produce -->EngineA" << endl;
     33     }
     34 };
     35 //type B of Engine
     36 class CEngineB :public CEngine{
     37 public:
     38     CEngineB()
     39     {
     40     }
     41     ~CEngineB()
     42     {
     43     }
     44     void getStyleOfEngine()
     45     {
     46         cout << "Produce -->EngineB" << endl;
     47     }
     48 };
     49 
     50 
     51 //Aircondition
     52 class CAircondition{
     53 public:
     54     CAircondition()
     55     {
     56     }
     57     ~CAircondition()
     58     {
     59     }
     60     virtual void getStyleOfAircondition() = 0;
     61 };
     62 
     63 //type A of Aircondition
     64 class CAirconditionA :public CAircondition{
     65 public:
     66     CAirconditionA()
     67     {
     68     }
     69     ~CAirconditionA()
     70     {
     71     }
     72     void getStyleOfAircondition()
     73     {
     74         cout << "Produce -->AirconditionA" << endl;
     75     }
     76 };
     77 //type B of Aircondition
     78 class CAirconditionB :public CAircondition{
     79 public:
     80     CAirconditionB()
     81     {
     82     }
     83     ~CAirconditionB()
     84     {
     85     }
     86     void getStyleOfAircondition()
     87     {
     88         cout << "Produce -->AirconditionB" << endl;
     89     }
     90 };
     91 
     92 //Abstract Class Of Factory
     93 class CFactoryBMW{
     94 public:
     95     CFactoryBMW()
     96     {
     97     }
     98     ~CFactoryBMW()
     99     {
    100     }
    101     virtual CEngine* createEngine() = 0;
    102     virtual CAircondition* createAircondition() = 0;
    103 };
    104 
    105 //FactoryBMW Of BMW320
    106 //Produce Accessories For BMW320
    107 class CFactoryBMW320 :public CFactoryBMW{
    108 public:
    109     CFactoryBMW320()
    110     {
    111     }
    112     ~CFactoryBMW320()
    113     {
    114     }
    115     CEngine* createEngine()
    116     {
    117         return new CEngineA();
    118     }
    119     CAircondition* createAircondition()
    120     {
    121         return new CAirconditionA();
    122     }
    123 };
    124 
    125 //FactoryBMW Of BMW523
    126 //Produce Accessories For BMW523
    127 class CFactoryBMW523 :public CFactoryBMW{
    128 public:
    129     CFactoryBMW523()
    130     {
    131     }
    132     ~CFactoryBMW523()
    133     {
    134     }
    135     CEngine* createEngine()
    136     {
    137         return new CEngineB();
    138     }
    139     CAircondition* createAircondition()
    140     {
    141         return new CAirconditionB();
    142     }
    143 };
    144 
    145 //客户端
    146 int _tmain(int argc, _TCHAR** argv)
    147 {
    148     //About BMW320
    149     CFactoryBMW* factoryBMW320 = new CFactoryBMW320();
    150     CEngine* engineA = factoryBMW320->createEngine();
    151     engineA->getStyleOfEngine();
    152     CAircondition* airconditionA = factoryBMW320->createAircondition();
    153     airconditionA->getStyleOfAircondition();
    154     cout << "**------------------------------------------**" << endl;
    155     //About BMW523
    156     CFactoryBMW* factoryBMW523 = new CFactoryBMW523();
    157     CEngine* engineB = factoryBMW523->createEngine();
    158     engineB->getStyleOfEngine();
    159     CAircondition* airconditionB = factoryBMW523->createAircondition();
    160     airconditionB->getStyleOfAircondition();
    161 
    162     return 0;
    163 }

    运行结果:

    四、详谈抽象工厂模式

    起源:

      抽象工厂模式的起源或者最早的应用,是用于创建分属于不同操作系统的视窗构建。比如:命令按键(Button)与文字框(Text)都是视窗构建,在UNIX操作系统的视窗环境和Windows操作系统的视窗环境中,这两个构建有不同的本地实现,它们的细节有所不同。

      在每一个操作系统中,都有一个视窗构建组成的构建家族。在这里就是Button和Text组成的产品族。而每一个视窗构件都构成自己的等级结构,由一个抽象角色给出抽象的功能描述,而由具体子类给出不同操作系统下的具体实现。

      可以发现在上面的产品类图中,有两个产品的等级结构,分别是Button等级结构和Text等级结构同时有两个产品族,也就是UNIX产品族和Windows产品族。UNIX产品族由UNIX Button和UNIX Text产品构成;而Windows产品族由Windows Button和Windows Text产品构成。

      系统对产品对象的创建需求由一个工程的等级结构满足,其中有两个具体工程角色,即UnixFactoryWindowsFactory。UnixFactory对象负责创建Unix产品族中的产品,而WindowsFactory对象负责创建Windows产品族中的产品。这就是抽象工厂模式的应用,抽象工厂模式的解决方案如下图:

      

    抽象工厂模式定义:

      Provide an interface for creating families of related or dependent objects without specifying their concrete classes 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类。

      抽象工厂的通用类图如下图所示。

      

    虽然抽象工厂模式的类繁多,但是主要还是分为四类:

    1)AbstractFactory:抽象工厂角色,它声明了一组用于创建不同产品的方法(函数),每一个方法对应一种产品,如本文开头对应的发动机产品和空调产品,在抽象工厂角色中对应的方法为:

    1 virtual CEngine* createEngine() = 0;
    2 virtual CAircondition* createAircondition() = 0;

    2)ConcreteFactory:具体工厂角色,它实现了在抽象工厂中定义的创建产品的方法,生成一组具体产品这些产品构成一个产品种类,每一个产品都位于某个产品登记结构中。如文中开头的CFactoryBMW320类,是专门用于生产BMW320车型的所有配件的工厂;CFactoryBMW523类是专门用于生产BMW523车型的所有配件的工厂。

    3)AbstractProduct:抽象产品角色(对应抽象类CEngine和CAircondition),它定义了几种产品的基本行为

    4)ConcreteProduct:具体产品角色(对应CEngineA、CEngineB、CAirconditionA和CAirconditionB四个实现类),它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法

    抽象工厂模式与工厂方法的区别:


    工厂方法模式
    一个抽象产品类,可以派生出多个具体产品类。   
    一个抽象工厂类,可以派生出多个具体工厂类。   
    每个具体工厂类只能创建一个具体产品类的实例。
    抽象工厂模式
    多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。   
    一个抽象工厂类,可以派生出多个具体工厂类。   
    每个具体工厂类可以创建多个具体产品类的实例。   
    区别
    工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。   
    工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。


    抽象工厂模式的优点:

    1)封装性,每个产品的实现类不是高层模块要关心的,要关心的是什么?是接口,是抽象,它不关心对象是如何创建出来,这由谁负责呢?工厂类,只要知道工厂类是谁,我就能创建出一个需要的对象,省时省力,优秀设计就应该如此。

    2)产品族内的约束为非公开状态。对调用工厂类的高层模块来说,它不需要知道这个约束,我就是要一辆汽车,自动挡的,你别在自动挡的车上给我装个离合器就好。具体你要怎么做,我并不关心。

    抽象工厂模式的缺点:

      抽象工厂模式的最大缺点就是产品族扩展非常困难,违反了开闭原则。

    五、总结

      无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。
      所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

    参考:http://blog.csdn.net/jason0539/article/details/44976775

  • 相关阅读:
    FileManager(文件管理类)
    XE6 IntraWeb.v14.0.32安装及破解指南
    在应收应付系统凭证做冲销后,如何取消冲销?
    delphi将图片保存到SQL数据库和读取图片
    去掉cxgrid 中的过滤下拉箭头
    CxGrid 分组以后自动排序了,可以禁止自动排序吗
    最简单解决CHM文件无法显示的办法
    用友T3、T6常见问题
    SQL2005还原数据库3154错误
    cxGrid 怎样才能让不自动换行 WordWrap:=false
  • 原文地址:https://www.cnblogs.com/codingmengmeng/p/5923300.html
Copyright © 2011-2022 走看看