zoukankan      html  css  js  c++  java
  • 设计模式---对象创建模式之抽象工厂模式(Abstract Factory)

    一:概念

    抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的。
    抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象

    二:动机

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

    三:和工厂方法模式区别

    工厂模式只能生产一个产品
    抽象工厂可以一次生产一个产品族

    四:代码讲解(连接不同数据库)

    (一)原代码

    class EmployeeDAO{
        
    public:
        vector<EmployeeDO> GetEmployees(){
            SqlConnection* connection =  //数据库连接
                new SqlConnection();
            connection->ConnectionString = "...";
    
            SqlCommand* command =  //数据库命令
                new SqlCommand();
            command->CommandText="...";
            command->SetConnection(connection);
    
            SqlDataReader* reader = command->ExecuteReader();  //数据库信息读取
            while (reader->Read()){
    
            }
        }
    };

    问题提出:

    需求更改:需要变更数据库mysql,oracle,sqlite等
    所以new是不合适的,是静态特质,定死了。这个类就不适用于多种数据库变化的可能

    (二)支持面向接口编程

    //数据库访问有关的基类
    class IDBConnection{
        
    };
    
    class IDBCommand{
        
    };
    
    class IDataReader{
        
    };
    
    //支持SQL Server
    class SqlConnection: public IDBConnection{
        
    };
    
    class SqlCommand: public IDBCommand{
        
    };
    
    class SqlDataReader: public IDataReader{
        
    };
    
    //支持Oracle
    class OracleConnection: public IDBConnection{
        
    };
    
    class OracleCommand: public IDBCommand{
        
    };
    
    class OracleDataReader: public IDataReader{
        
    };
    class EmployeeDAO{
        
    public:
        vector<EmployeeDO> GetEmployees(){
            SqlConnection* connection =
                new SqlConnection();
            connection->ConnectionString = "...";
    
            SqlCommand* command =
                new SqlCommand();
            command->CommandText="...";
            command->SetConnection(connection);
    
            SqlDataReader* reader = command->ExecuteReader();
            while (reader->Read()){
    
            }
    
        }
    };
    从上篇文章可以知道new是不好的,需要编译时依赖。所以我们想办法使用工厂模式修改去掉new

    (三)添加工厂

    //数据库访问有关的基类
    class IDBConnection{
        
    };
    class IDBConnectionFactory{
    public:
        virtual IDBConnection* CreateDBConnection()=0;
    };
    
    
    class IDBCommand{
        
    };
    class IDBCommandFactory{
    public:
        virtual IDBCommand* CreateDBCommand()=0;
    };
    
    
    class IDataReader{
        
    };
    class IDataReaderFactory{
    public:
        virtual IDataReader* CreateDataReader()=0;
    };
    
    
    //支持SQL Server
    class SqlConnection: public IDBConnection{
        
    };
    class SqlConnectionFactory:public IDBConnectionFactory{
        
    };
    
    
    class SqlCommand: public IDBCommand{
        
    };
    class SqlCommandFactory:public IDBCommandFactory{
        
    };
    
    
    class SqlDataReader: public IDataReader{
        
    };
    class SqlDataReaderFactory:public IDataReaderFactory{
        
    };
    
    //支持Oracle
    class OracleConnection: public IDBConnection{
        
    };
    
    class OracleCommand: public IDBCommand{
        
    };
    
    class OracleDataReader: public IDataReader{
        
    };
    
    //.....也有Oracle相关工厂
    class EmployeeDAO{
       //根据下面抽象基类,我们可以来创建SQL,Oracle等多种数据库 IDBConnectionFactory
    * dbConnectionFactory; IDBCommandFactory* dbCommandFactory; IDataReaderFactory* dataReaderFactory; public: vector<EmployeeDO> GetEmployees(){ IDBConnection* connection = dbConnectionFactory->CreateDBConnection(); connection->ConnectionString("..."); IDBCommand* command = dbCommandFactory->CreateDBCommand(); command->CommandText("..."); command->SetConnection(connection); //关联性 IDBDataReader* reader = command->ExecuteReader(); //关联性 while (reader->Read()){ } } };
    勉强解决了变更数据库的问题

    新的问题:

        IDBConnectionFactory* dbConnectionFactory;
        IDBCommandFactory* dbCommandFactory;
        IDataReaderFactory* dataReaderFactory;
    我们若是传入3个不同的变量,mysql的连接,Oracle的命令,sqlite的读取,那么就会报错,紊乱,因为原来这三个是有关联的
            IDBConnection* connection =
                dbConnectionFactory->CreateDBConnection();
            connection->ConnectionString("...");
    
            IDBCommand* command =
                dbCommandFactory->CreateDBCommand();
            command->CommandText("...");
            command->SetConnection(connection); //关联性
    
            IDBDataReader* reader = command->ExecuteReader(); //关联性
    什么样的数据库就和什么样的命令相关联,数据库连接对于每个数据库也是不一样的,所以,我们需要要保证关联性一致

    (四)引出抽象工厂

    //数据库访问有关的基类
    class IDBConnection{
        
    };
    
    class IDBCommand{
        
    };
    
    class IDataReader{
        
    };
    
    
    class IDBConnectionFactory{
    public:
        virtual IDBConnection* CreateDBConnection()=0;
    };
    
    class IDBCommandFactory{
    public:
        virtual IDBCommand* CreateDBCommand()=0;
    };
    
    class IDataReaderFactory{
    public:
        virtual IDataReader* CreateDataReader()=0;
    };
    我们发现3个类的相关性很强,那么我们就可以使用一个工厂来实现:高内聚
    //数据库访问有关的基类
    class IDBConnection{
        
    };
    
    class IDBCommand{
        
    };
    
    class IDataReader{
        
    };
    
    
    class IDBFactory{
    public:
        virtual IDBConnection* CreateDBConnection()=0;
        virtual IDBCommand* CreateDBCommand()=0;
        virtual IDataReader* CreateDataReader()=0;
    };
    //支持SQL Server
    class SqlConnection: public IDBConnection{
        
    };
    class SqlCommand: public IDBCommand{
        
    };
    class SqlDataReader: public IDataReader{
        
    };
    
    
    class SqlDBFactory:public IDBFactory{
    public:
        virtual IDBConnection* CreateDBConnection()=0;
        virtual IDBCommand* CreateDBCommand()=0;
        virtual IDataReader* CreateDataReader()=0;
     
    };
    //支持Oracle
    class OracleConnection: public IDBConnection{
        
    };
    
    class OracleCommand: public IDBCommand{
        
    };
    
    class OracleDataReader: public IDataReader{
        
    };
    
    class OracleDBFactory:public IDBFactory{
    public:
        virtual IDBConnection* CreateDBConnection()=0;
        virtual IDBCommand* CreateDBCommand()=0;
        virtual IDataReader* CreateDataReader()=0;
    };
    class EmployeeDAO{
        IDBFactory* dbFactory;
        
    public:
        vector<EmployeeDO> GetEmployees(){
            IDBConnection* connection =
                dbFactory->CreateDBConnection();
            connection->ConnectionString("...");
    
            IDBCommand* command =
                dbFactory->CreateDBCommand();
            command->CommandText("...");
            command->SetConnection(connection); //关联性
    
            IDBDataReader* reader = command->ExecuteReader(); //关联性
            while (reader->Read()){
    
            }
        }
    };

    五:模式定义

    提供一个接口,让该接口负责创建一系列“相关或相互依赖的对象”,无需指定它们具体的类。 
    
                                                                                 --《设计模式》Gof

    六:类图(结构)

    其中还少了一个抽象产品IDataReader,就可以和上面代码对应上了。

    七:要点总结

    (一)如果没有应对“多系列对象构建”的需求变化,则没有必要使用 Abstract Factory 模式,这时候使用简单的工厂完全可以。

    (二)“系列对象”指的是在某一特定系列下的对象之间具有相互依赖或作用的关系。不同系列的对象之间不能相互依赖。

    (三)Abstract Factory 模式主要在于应对“新系列”的需求变动,其缺点在于难以应对“新对象”的需求变动。

    新系列:是指mysql,Oracle,sqlite等各是一个系列
    新对象的需求变化:像是连接,命令,查询,我们若是再添加一个变动到抽象基类,可以往往不适用全部的系列(抽象基类要求稳定)

    八:案例实现(南北水果族)

    class Fruit
    {
    public:
        virtual void sayname() = 0;
        virtual ~Fruit(){}
    };
    
    class FruitFactory
    {
    public:
        virtual Fruit* getApple() = 0;
        virtual Fruit* getBanana() = 0;
        virtual ~FruitFactory(){};
    };
    class NorthApple :public Fruit
    {
    public:
        virtual void sayname()
        {
            cout << "you get a north apple" << endl;
        }
    };
    
    class NorthBanana :public Fruit
    {
    public:
        virtual void sayname()
        {
            cout << "you get a north banana" << endl;
        }
    };
    
    class NorthFruitFactory :public FruitFactory
    {
    public:
        virtual Fruit* getApple()
        {
            return new NorthApple();
        }
    
        virtual Fruit* getBanana()
        {
            return new NorthBanana();
        }
    };
    class SouthApple :public Fruit
    {
    public:
        virtual void sayname()
        {
            cout << "you get a south apple" << endl;
        }
    };
    
    class SouthBanana :public Fruit
    {
    public:
        virtual void sayname()
        {
            cout << "you get a south banana" << endl;
        }
    };
    
    class SouthFruitFactory :public FruitFactory
    {
    public:
        virtual Fruit* getApple()
        {
            return new SouthApple();
        }
    
        virtual Fruit* getBanana()
        {
            return new SouthBanana();
        }
    };
    void main()
    {
        FruitFactory *ff = new NorthFruitFactory();
        Fruit* ap = ff->getApple();
        Fruit* ba = ff->getBanana();
        ap->sayname();
        ba->sayname();
        system("pause");
        return;
    }

  • 相关阅读:
    tuple 元组及字典dict
    day 49 css属性补充浮动 属性定位 抽屉作业
    day48 选择器(基本、层级 、属性) css属性
    day47 列表 表单 css初识
    day 46 http和html
    day 45索引
    day 44 练习题讲解 多表查询
    day 40 多表查询 子查询
    day39 表之间的关联关系、 补充 表操作总结 where 、group by、
    day38 数据类型 约束条件
  • 原文地址:https://www.cnblogs.com/ssyfj/p/9537338.html
Copyright © 2011-2022 走看看