• 第5章 创建型模式—抽象工厂模式


    1. 抽象工厂的定义

    (1)提供一个创建一系列相关相互依赖对象的接口,而无需指定它们具体的类

      ①只需要知道创建一系列对象的接口,而无需知道具体使用的是哪一个实现

      ②这一系列对象是相关或相互依赖的,也就是说既要创建对象,还要约束它们之间的关系。

      ③一系列对象是构建新对象所需要的组成部分,并且对象之间相互有约束。如电脑由CPU和主板等组成,但CPU的针脚数和主板提供的插口必须是匹配的,否则无法组装。

     

    (2)产品族和产品等级

     

      ①产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构,功能相关联的产品组成的家族。如,AMD的主板、芯片组、CPU组成一个家族,Intel的主板、芯片组、CPU组成一个家族。

      ②产品等级结构产品等级结构即产品的继承结构。如抽象电视机与具体品牌的电视机之间构成了一个产品等级结构。如,AMD和Intel这两个家族都来自于三个产品等级:主板、芯片组、CPU。一个等级结构是由相同的结构的产品组成。

    (2)抽象工厂模式的结构图

     

      ①Abstract Factory:抽象工厂,定义创建一系列产品对象的操作接口

      ②Concrete Factory:具体的工厂,实现抽象工厂定义的方法,具体实现一系列对象的创建。

      ③Abstract Product:定义一类产品对象的接口

      ④Concrete Product:具体的产品实现对象,通常在具体工厂里面,会选择具体的产品实现对象,来创建符合抽象工厂类中定义的相应的接口类型对象。

      ⑤Client:客户端,主要使用抽象工厂来获取一系列所需要的产品对象,然后面向这些产品对象的接口编程。

    2. 思考抽象工厂模式

    (1)抽象工厂模式的本质:选择产品簇的实现,即每个具体工厂创建的是一系列的产品。

      ①工厂方法针对的是单个产品对象的创建,本质是选择单个产品的实现。而抽象工厂着重的是创建一个产品簇的实现,在抽象工厂类里定义的接口通常是有联系的,它们都是产品的某一部分或者是相互依赖的。注意,这些接口不是任意堆砌的,而是一系列相关或相互依赖的方法。

      ②如果抽象工厂里面只定义一个方法,直接创建产品,那就退化为工厂方法了。

    (2)切换产品簇:只要提供不同的抽象工厂实现,产品簇就可以作为一个整体被切换

    【编程实验】电脑装机方案

    //创建型模式:抽象工厂模式
    //电脑组装
    #include <stdio.h>
    
    ////////////////////////////////////////////产品(等级)////////////////////////////
    //产品等级1:
    //1、抽象CPU类
    class CPUApi
    {
    public:
        virtual void calculate() = 0;
    };
    
    //1.1 AMD CPU(具体CPU产品类)
    class AMDCPU : public CPUApi
    {
    private:
        int pints;
    public:
        AMDCPU(int pints){this->pints = pints;}
        void calculate()
        {
            printf("now in AMD CPU, pints = %d
    ",pints);
        }    
    };
    
    //1.2 Intel CPU(具体CPU产品类)
    class IntelCPU : public CPUApi
    {
    private:
        int pints;
    public:
        IntelCPU(int pints){this->pints = pints;}
        void calculate()
        {
            printf("now in Intel CPU, pints = %d
    ",pints);
        }    
    };
    
    //产品等级2
    //2.抽象主板类
    class MainboardApi
    {
    public:
        virtual void installCPU() = 0;  
    };
    
    //2.1 技嘉主板
    class GAMainboard : public MainboardApi
    {
    private:
        int cpuHoles; //CPU插槽的孔数
    public:
        GAMainboard(int cpuHoles){this->cpuHoles = cpuHoles;}
        void installCPU()
        {
            printf("now in GAMainboard, cpuHoles = %d
    ", cpuHoles);    
        }    
    };
    
    //2.2 微星主板
    class MSIMainboard : public MainboardApi
    {
    private:
        int cpuHoles; //CPU插槽的孔数
    public:
        MSIMainboard(int cpuHoles){this->cpuHoles = cpuHoles;}
        void installCPU()
        {
            printf("now in MSIMainboard, cpuHoles = %d
    ", cpuHoles);    
        }    
    };
    
    ////////////////////////////////////////////工厂类////////////////////////////
    //3.抽象工厂接口,声明创建抽象产品对象的操作
    class AbstractFactory
    {
    public:
        //创建CPU对象
        virtual CPUApi* createCPUApi() = 0;
        
        //创建主板对象
        virtual MainboardApi* createMainboardApi() = 0;    
    };
    
    //3.1具体工厂(装机方案1):Intel的CPU+技嘉主板
    //  这里创建的CPU和主板对象是能匹配的,即有约束关系  
    class Schema1 : public AbstractFactory
    {
    public:
        //CPU
        CPUApi* createCPUApi()
        {
            return new IntelCPU(1156);
        }
        
        //主板对象
        MainboardApi* createMainboardApi()
        {
            return new GAMainboard(1156);
        }    
    };
    
    //3.2具体工厂(装机方案2):AMD的CPU+微星主板
    //  这里创建的CPU和主板对象是能匹配的,即有约束关系  
    class Schema2 : public AbstractFactory
    {
    public:
        //CPU
        CPUApi* createCPUApi()
        {
            return new AMDCPU(939);
        }
        
        //主板对象
        MainboardApi* createMainboardApi()
        {
            return new MSIMainboard(939);
        }    
    };
    
    int main()
    {
        //客户端调用例子
        
        //工厂
        AbstractFactory* af = new Schema1(); //可以整体换装机方案
        
        //CPU
        CPUApi* cpu = af->createCPUApi();
        
        //主板
        MainboardApi* mainboard = af->createMainboardApi();
        
        //测试一下配件是否正常
        cpu->calculate();
        mainboard->installCPU();
        
        delete cpu;
        delete mainboard;
        delete af;
        
        return 0;
    }

    3. 抽象工厂模式的优缺点

    (1)优点

      ①封装性:抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。

      ②当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象(即产品对象是有约束的,不可以随心所欲的创建对象)。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。

      ③增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”

    (2)缺点

      ①在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。

      ②开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

    4. 抽象工厂模式的使用场景

    (1)一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。

    (2)这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品

    (3)同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束(比如:Intel主板必须使用Intel CPU、Intel芯片组),就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点

    5. 抽象工厂模式和DAO

    (1)数据访问对象(Data Access Object,DAO):用于解决访问数据对象所面临的一系列问题。

      ①数据源不同,如本地数据源和远程服务器上的数据源

      ②存储类型不同(如关系型数据库(RDBMS)、XML、纯文件等。

      ③访问方式不同,比如ODBC、ADO

      ④供应商不同,如Oracle、DB2、SqlServer、MySQL等等。

      ⑤版本不同,如关系型数据库,不同版本,实现功能是有差异的。就算是对标准的SQL的支持,也是有差异的。

     

    (2)DAO和抽象工厂的关系

      ①DAO模式最常见的实现策略是工厂的策略,而且多是通过抽象工厂模式来实现。

      ②在使用抽象工厂模式时,也可以结合工厂方法模式。

    (3)DAO访问方式的工厂实现策略(以订单处理为例)

      ①订单通常分为主记录(主表)和明细记录(子表)

      ②当业务对象需要操作订单的主表时,一般也需要操作子表

      ③如果业务简单,且对数据的操作是固定的,即不管订单业务如何变化,底层数据存储都是一样的,那么这时可以采用工厂方法模式。如果底层存储不固定(如存在数据库,或Xml文件),则一般采用抽象工厂模式

     

    【编程实例】利用抽象工厂模式将业务对象存储在不同的数据仓库

    //创建型模式:抽象工厂模式
    //数据访问对象策略的抽象工厂实现
    #include <stdio.h>
    
    //以下的所说的数据仓库可以是关系型系数据库或Xml
    
    //产品对象的接口,就是订单主、子记录的DAO定义
    //订单主记录的DAO定义:(提供保存业务对象到数据仓库的功能
    class COrderMainDAO
    {
    public:
        virtual void saveOrderMain() = 0;
    };
    
    //订单子记录的DAO定义(提供保存业务对象到数据仓库的功能
    class COrderDetailDAO
    {
    public:
        virtual void saveOrderDetail() = 0;   
    };
    
    //Rdb实现:将业务对象保存到关系型数据库
    class CRdbMainDAOImpl : public COrderMainDAO
    {
    public:
        void  saveOrderMain()
        {
            printf("now in RdbMainDAOImpl saveOrderMain
    ");
        }   
    };
    
    //Rdb实现:将业务对象保存到关系型数据库
    class CRdbDetailDAOImpl : public COrderDetailDAO
    {
    public:
        void  saveOrderDetail()
        {
            printf("now in RdbDetailDAOImpl saveOrderDetail
    ");
        }   
    };
    
    //Xml实现:将业务对象保存到xml文件
    class CXmlMainDAOImpl : public COrderMainDAO
    {
    public:
        void saveOrderMain()
        {
            printf("now in XmlMainDAOImpl saveOrderMain
    ");        
        }
    };
    
    //Xml实现:将业务对象保存到xml文件
    class CXmlDetailDAOImpl : public COrderDetailDAO
    {
    public:
        void  saveOrderDetail()
        {
            printf("now in XmlDetailDAOImpl saveOrderDetail
    ");
        }   
    };
    
    
    //抽象工厂,创建订单主、子记录对应的DAO对象
    class CDAOFactory
    {
    public:
        //订单主记录对应的DAO对象
        virtual COrderMainDAO* createOrderMainDAO() = 0; 
        
        //订单子记录对应的DAO对象
        virtual COrderDetailDAO* createOrderDetailDAO() = 0;
    };
    
    //具体工厂
    //关系型数据库的实现方式
    class CRdbDAOFactory : public CDAOFactory
    {
    public:
        COrderMainDAO* createOrderMainDAO()
        {
            return new CRdbMainDAOImpl();
        }   
        
        COrderDetailDAO* createOrderDetailDAO()
        {
            return new CRdbDetailDAOImpl();
        }    
    };
    
    //Xml的实现方式
    class CXmlDAOFactory : public CDAOFactory
    {
    public:
        COrderMainDAO* createOrderMainDAO()
        {
            return new CXmlMainDAOImpl();
        }   
        
        COrderDetailDAO* createOrderDetailDAO()
        {
            return new CXmlDetailDAOImpl();
        }    
    };
    
    
    int main()
    {
        //客户端调用例子
        
        //创建DAO的抽象工厂
        //CDAOFactory* df = new CRdbDAOFactory();
        CDAOFactory* df = new CXmlDAOFactory();
        
        //通过抽象工厂来获取需要的DAO接口
        COrderMainDAO* mainDAO = df->createOrderMainDAO();
        COrderDetailDAO* detailDAO = df->createOrderDetailDAO();
        
        //调用DAO来完成数据存储的功能
        mainDAO->saveOrderMain();
        detailDAO->saveOrderDetail();
        
        delete mainDAO;
        delete detailDAO;
        delete df;
     
        return 0;
    }
  • 相关阅读:
    结对第一次—原型设计(文献摘要热词统计)
    第一次作业-准备篇
    Alpha冲刺Day9
    Alpha冲刺Day8
    Alpha冲刺Day7
    Alpha冲刺Day6
    Alpha冲刺Day5
    Alpha冲刺Day4
    Alpha冲刺Day3
    Alpha冲刺Day2
  • 原文地址:https://www.cnblogs.com/5iedu/p/5499351.html
Copyright © 2020-2023  润新知