我希望有一个工厂来创建客户端的句柄对象,所以我为句柄类定义了一个接口,但是我遇到了客户端在创建句柄对象后必须初始化的困难。问题是初始化取决于句柄类型。
我能做的最好的是下面的代码,但在此实现中,客户端可以使用错误的数据类型进行初始化。我尝试使用模板处理这个问题,但我找不到一个好的解决方案。
我该如何处理这个初始化问题?也许工厂不是最好的方式?
#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!!!
}