0

我想有一个工厂用于客户端创建句柄对象,所以我为句柄类定义了一个接口,但是我面临着客户端在创建句柄对象后必须初始化的困难。问题是初始化取决于句柄类型。

我能做的最好的就是下面的代码,但是在这个实现中,客户端可以用错误的数据类型进行初始化。我尝试使用模板来处理这个问题,但我找不到一个好的解决方案。

我该如何处理这个初始化问题?也许工厂不是最好的方法?

#include <iostream>
#include <map>
#include <vector>
#include <string>

// type erasure for data type use in handle class
class HandleDataType
{
public:
    HandleDataType() : datatype("notype") {};
    HandleDataType(std::string s) : datatype(s) {};
public:
    std::string datatype;
};
class HandleDataTypeInt : public HandleDataType //simplify data type
{
    int data;
public:
    HandleDataTypeInt(int a) : data(a), HandleDataType("int")  {};
};
class HandleDataTypeDouble : public HandleDataType //simplify data type
{
    double data;
public:
    HandleDataTypeDouble(double a) : data(a),  HandleDataType("double")  {};
};

//class prototype 
template <class T>
class Prototype
{
public:
    virtual ~Prototype(){}  
    virtual T* Clone() const =0 ;
};

class HandleI : public  Prototype<HandleI>
{
    //Attribute
private:
    unsigned int        m_id;
    std::string         m_handletype;
    std::string         m_name;
    HandleDataType*     m_data;//m_data type depends of handleI subclass

public:
    //Constructor
    HandleI() {};
    HandleI(std::string type) : m_handletype(type) {};
    HandleI(std::string type, unsigned int id, std::string name) : m_handletype(type), m_id(id), m_name(name) {};
    ~HandleI() {};

    //get
    std::string     get_handletype() const {return m_handletype;};
    std::string     get_handlename() const {return m_name;};
    unsigned int    get_handleid()   const {return m_id;};
    HandleDataType* get_data()       const {return m_data;};

    // set
    void        set_name(const std::string name)    {m_name=name;};
    void        set_id(const unsigned int id)       {m_id=id;};
    void        set_data(HandleDataType & d)        {m_data=new HandleDataType(d);};

    //  virtual method if interface
public:
    virtual void            precompute() =0;
    virtual void            compute() =0;
};
// Handle Interface
class HandleInt : public HandleI
{
public:
    // constructor;
    HandleInt() : HandleI("HandleInt") {};
    HandleInt(unsigned int id, std::string name) : HandleI("HandleInt", id, name) {};
    ~HandleInt() {};

    // implementation of virtual method
public:
    // clone method from prototype for fabric
    HandleI*        Clone() const   {return new HandleInt(*this);}
    // inteface method
    void            precompute()    {std::cout<< "precomputeInt" << std::endl;}
    void            compute()       {std::cout<< "computeInt" << std::endl;}
};


class HandleDouble : public HandleI
{
public:
    // constructor;
    HandleDouble() : HandleI("HandleDouble") {};
    HandleDouble(unsigned int id, std::string name) : HandleI("HandleDouble", id, name) {};
    ~HandleDouble() {};

    // implementation of virtual method
public:         
    // clone method from prototype for fabric
    HandleI*        Clone() const   {return new HandleDouble(*this);}
    // inteface method
    void            precompute()    {std::cout<< "precomputeDouble" << std::endl;}
    void            compute()       {std::cout<< "computeDouble" << std::endl;}
};

class FactoryHandle
{
private :
    std::map<std::string, HandleI*> m_handleReference;

public :
    FactoryHandle()
    {
        m_handleReference["INT"] = new HandleInt() ;
        m_handleReference["DOUBLE"] = new HandleDouble() ;
    }
    HandleI* createHandle(std::string htype)
    {
        return m_handleReference[htype]->Clone();
    }
    ~FactoryHandle()
    {
        std::map<std::string, HandleI*>::iterator it;
        for (it=m_handleReference.begin(); it!=m_handleReference.end(); ++it)
            delete it->second;
        m_handleReference.clear();
    }
};

int main()
{
    HandleDataTypeInt * dataint = new HandleDataTypeInt(1);
    HandleDataTypeDouble * datadouble = new HandleDataTypeDouble(1.0);

    FactoryHandle* fh = new FactoryHandle() ;
    HandleI *   hint = fh->createHandle("INT");
    // initialise the handle hint
    hint->set_id(1);
    hint->set_name("test_int");
    hint->set_data(*dataint);
    //
    std::cout << hint->get_handletype() << std::endl;
    std::cout << hint->get_handleid() << std::endl;
    std::cout << hint->get_handlename() << std::endl;
    hint->compute();
    std::cout << hint->get_data()->datatype << std::endl;


    // but the client can also initialize with data of the wrong type like this
    //hint->set_data(*datadouble); -> i won't authorise such initalisation
    hint->set_id(1);
    hint->set_name("test_int");
    hint->set_data(*datadouble);
    //
    std::cout << hint->get_handletype() << std::endl;
    std::cout << hint->get_handleid() << std::endl;
    std::cout << hint->get_handlename() << std::endl;
    hint->compute();
    std::cout << hint->get_data()->datatype << std::endl; // we have here a double data type!!!
}
4

0 回答 0