Factory design pattern and abstract factory design pattern

Posted by smonkcaptain on Tue, 14 Dec 2021 11:56:58 +0100

Factory design mode

1. Definition

Define an interface for creating objects and let subclasses decide which class to instantiate. Factory Method delays the instantiation of a class to subclasses—— Design patterns GoF

2. Code implementation

Code background: implement an interface to export data, allowing customers to choose the export method of data

#include <string>
// Realize the interface for exporting data. The format of exported data includes xml, json, text format txt, and excel format csv may be extended later
class IExport {
public:
    virtual bool Export(const std::string &data) = 0;
    virtual ~IExport(){}
};

class ExportXml : public IExport {
public:
    virtual bool Export(const std::string &data) {
        
        //...
        //Xml mode output

        return true;
    }
};

class ExportJson : public IExport {
public:
    virtual bool Export(const std::string &data) {

        //...
        //Json mode output

        return true;
    }
};

class ExportTxt : public IExport {
public:
    virtual bool Export(const std::string &data) {

        //...
        //TX mode output

        return true;
    }
};

//==========================================The above is the working class, and the following is the corresponding factory class==================================================

class IExportFactory {
public:
    IExportFactory() {
        _export = nullptr;
    }

    virtual ~IExportFactory() {
        if (_export) {
            delete _export;
            _export = nullptr;
        }
    }

    //Call the Export function of the object itself
    bool Export(const std::string &data) {
        if (_export == nullptr) {
            _export = NewExport();
        }
        return _export->Export(data);
    }
protected:
    virtual IExport * NewExport(/* ... */) = 0;   //The advantage of factory mode is that it hides the complex process of creating objects, and the external world can directly use the created objects
private:
    IExport* _export;
};

class ExportXmlFactory : public IExportFactory {
protected:
    virtual IExport * NewExport(/* ... */) {   
        // There may be other operations, or many parameters
        IExport * temp = new ExportXml();
        // What may be done later
        return temp;
    }
};
class ExportJsonFactory : public IExportFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // There may be other operations, or many parameters
        IExport * temp = new ExportJson;
        // What may be done later
        return temp;
    }
};
class ExportTxtFactory : public IExportFactory {
protected:
    IExport * NewExport(/* ... */) {
        // There may be other operations, or many parameters
        IExport * temp = new ExportTxt;
        // What may be done later
        return temp;
    }
};


int main () {
    IExportFactory * Txt_factory = new ExportTxtFactory();
    Txt_factory->Export("hello world");
    return 0;
}

Code analysis:

  • First, create an abstract interface class to standardize the code; All newly extended interface output classes inherit this interface and implement the function of how to output data
  • Create a general abstract factory class, then create the factory class corresponding to the interface output class, and inherit this abstract factory class
  • In the factory class corresponding to each interface output method: implement the creation process of interface output class. Because the object creation process is complex, it is left to the factory to create (the factory is used to create objects)
  • The created object can be returned to the user, or you can call the function in the object to complete a specific function

Summary: the factory is used to create objects, especially objects that require many initialization parameters, so that the outside world does not care about the creation process, but only about the use

3. Key points

  • Solve the complex creation process and want to hide these details

    • Such as connection pool and thread pool
  • Hidden object real type (polymorphism is used)

  • There are many parameters to determine how to create an object, and the factory does this work. The outside world can directly use the created object

4. Essence

  • Delay to subclass to select the implementation - > subclass refers to the factory subclass. You can get the desired object by creating the corresponding factory class object

5. Structure diagram

Abstract factory design pattern

1. Definition

Provide an interface that is responsible for creating a series of "related or interdependent objects" without specifying their specific classes—— Design patterns GoF

2. Code implementation

Code background: implement an interface with export and import data, allowing customers to select the export and import method of data;

#include <string>
// Realize the interface of importing and exporting data. The formats of importing and exporting data include xml, json, text format txt, and excel format csv may be extended behind
class IExport {
public:
    virtual bool Export(const std::string &data) = 0;
    virtual ~IExport(){}
};

class ExportXml : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};

class ExportJson : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};

class ExportTxt : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};

//==========================================Above is the export==================================================

class IImport {
public:
    virtual bool Import(const std::string &data) = 0;
    virtual ~IImport(){}
};

class ImportXml : public IImport {
public:
    virtual bool Import(const std::string &data) {
        return true;
    }
};

class ImportJson : public IImport {
public:
    virtual bool Import(const std::string &data) {
        return true;
    }
};

class ImportTxt : public IImport {
public:
    virtual bool Import(const std::string &data) {
        return true;
    }
};

//==========================================Above is import==================================================

class IDataApiFactory {
public:
    IDataApiFactory() {
        _export = nullptr;
        _import = nullptr;
    }
    virtual ~IDataApiFactory() {
        if (_export) {
            delete _export;
            _export = nullptr;
        }
        if (_import) {
            delete _import;
            _import = nullptr;
        }
    }

    bool Export(const std::string &data) {
        if (_export == nullptr) {
            _export = NewExport();  //When the subclass overrides NewExport, the subclass is called
        }
        return _export->Export(data);
    }
    bool Import(const std::string &data) {
        if (_import == nullptr) {
            _import = NewImport();  //When the subclass overrides NewExport, the subclass is called
        }
        return _import->Import(data);
    }
protected:
    virtual IExport * NewExport(/* ... */) = 0;
    virtual IImport * NewImport(/* ... */) = 0;
private:
    IExport *_export;
    IImport *_import;
};

class XmlApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // There may be other operations, or many parameters
        IExport * temp = new ExportXml;
        // What may be done later
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // There may be other operations, or many parameters
        IImport * temp = new ImportXml;
        // What may be done later
        return temp;
    }
};

class JsonApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // There may be other operations, or many parameters
        IExport * temp = new ExportJson;
        // What may be done later
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // There may be other operations, or many parameters
        IImport * temp = new ImportJson;
        // What may be done later
        return temp;
    }
};
class TxtApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // There may be other operations, or many parameters
        IExport * temp = new ExportTxt;
        // What may be done later
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // There may be other operations, or many parameters
        IImport * temp = new ImportTxt;
        // What may be done later
        return temp;
    }
};



int main () {
    IDataApiFactory *factory = new TxtApiFactory();
    factory->Import("hello world");
    factory->Export("hello world");
    return 0;
}



Code analysis:

  • Different from ordinary factory classes, a factory class can create both corresponding export objects and import objects
  • Abstract factory design pattern: the associated classes can be placed in a factory class, and the corresponding objects can be created when necessary
    • In this example, the import and export of the TX mode are two functions, but both are related to the TX mode
    • You can put all classes related to the Txt function into the Txt factory. When a Txt function is needed, you can call the relevant function to create an object
    • According to the specific business requirements, you can return the object after creation, or you can directly call the member function of the object to realize some functions

Summary: the abstract factory design pattern is more extensible and can be used to extend multiple functions under the same type (e.g. import, export, transcoding, etc. in Txt mode)

3. Structure diagram

Topics: C++ Design Pattern