在下面的代码片段中,我需要通过工厂方法实例化对象,以便调用所选的适配器(即adapterTwovalue
),但在通过工厂方法调用时,我无法获得所需的结果。当我们分配静态声明对象的地址(即adapter = &at
)时,它可以工作但是在工厂中我通常得到空白输出。
我也尝试使用(adapter = new adapterTwo()
)来实例化对象,但输出字符串给出了空白结果。根据我的要求,我需要在connect
函数中填充所有getter,这是纯虚函数来构建响应。任何人都可以建议如何使用工厂方法实现这一点。
#include <iostream>
using namespace std;
class IAdapter
{
public:
enum FactoryList { AdapterOnevalue = 0, AdapterTwovalue };
virtual void connect() = 0;
static IAdapter* CreateList(FactoryList);
virtual ~IAdapter() {}
};
class LibraryOne
{
string property;
public:
void SetConnection(string property)
{
this->property = property;
}
string getConnection()const
{
return property;
}
};
//LibraryTwo
class LibraryTwo
{
string broker;
public:
void SetBroker(string broker1)
{
this->broker = broker1;
}
string getBroker() const
{
return broker;
}
};
//adapterOne
class AdapterOne : public IAdapter
{
LibraryOne one;
string constring;
public:
void SetClientconnection(string constring)
{
one.SetConnection(constring);
}
string GetClientconnection()
{
return one.getConnection();
}
void connect()
{
constring = GetClientconnection();
}
};
//Adapter to use library two
class AdapterTwo : public IAdapter
{
LibraryTwo two;
string brokerstring;
public:
void SetClientbroker(string constring)
{
two.SetBroker(constring);
}
string GetClientbroker()
{
return two.getBroker();
}
void connect()
{
string constring = GetClientbroker();
cout << "final value=" << constring;
}
};
IAdapter* IAdapter::CreateList(FactoryList SelectList)
{
IAdapter *ListObject;
switch (SelectList)
{
case AdapterOnevalue:
ListObject = new AdapterOne();
break;
case AdapterTwovalue:
ListObject = new AdapterTwo();
break;
default:
ListObject = NULL;
}
return ListObject;
}
int main()
{
IAdapter *adapter = 0;
//LibraryTwo obj;
AdapterTwo at;
at.SetClientbroker("amqp");
//cout << at.GetClientbroker();
//adapter = &at; it works
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);//it doesn't work
//Just do the operation now
adapter->connect();
return 0;
}
答案 0 :(得分:1)
使用您的代码我希望输出:final value=
。
它不会打印final value=amqp
,因为您需要在右侧适配器对象上调用SetClientbroker("amqp")
(在您的示例中为adapter
)。
无论如何,我会考虑在基类中放置一个虚方法SetString
,所以你可以这样做:
int main()
{
IAdapter *adapter = 0;
//LibraryTwo obj;
//AdapterTwo at;
//at.SetClientbroker("amqp");
//cout << at.GetClientbroker();
//adapter = &at; it works
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);//it doesn't work
//Just do the operation now
adapter->SetString("amqp");//<---------
adapter->connect();
return 0;
}
评论后编辑:
此时你需要施放物体(如@Aconcagua所建议的那样)。 但恕我直言,它根本不优雅。我认为你将失去工厂方法带来的好处。
答案 1 :(得分:1)
您可以在以下分享链接中看到完整的解决方案。
http://coliru.stacked-crooked.com/a/d8b9d32a1fa989c9
以下是解释。
(1)setClientBroker()或所有其他适配器相关的setter功能需要作为接口中的虚函数实现,默认参数值为“”(空字符串)。
(2)您需要始终在setter的派生类中使用override关键字(c ++ 11)功能,以便编译器在编译期间交叉检查是否正在覆盖正确的虚拟方法。
(3)不使用本地原始指针,总是使用智能指针。下面是 实现链接。
答案 2 :(得分:0)
IAdapter* adapter = nullptr;
AdapterTwo at;
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);
您已在此处创建了两个独立对象(在new
内调用createList
):at
并且adapter
指向。{ / p>
AdapterTwo at;
at.SetClientbroker("amqp");
现在确保在adapter
指向at
时获得预期输出,但其他对象如何知道您在第一个中设置的字符串?
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);
adapter->SetClientbroker("amqp"); // (*) !!!
您还需要在其他对象上设置代理。作为不同的对象,您甚至可以独立设置代理:
AdapterTwo at;
at.SetClientbroker("amqp");
IAdapter* adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);
adapter->SetClientbroker("aconcagua"); // (*) !!!
现在输出(如果你在两个对象上调用了connect
):
final value=amqp
final value=aconcagua
仅限:标记的行((*)
)不会编译,因为您的基类没有提供适当的setter!
现在有针对此问题的不同解决方案。例如,您可以投射对象:
// if you are REALLY 100% sure the object is of appropriate type:
static_cast<AdapterTwo*>(adapter)->setClientBroker("...");
// if NOT:
AdapterTwo* a2 = dynamic_cast<AdapterTwo*>(adapter);
if(a2)
a2->setClientBroker("...");
else
// appropriate error handling
你可以为set / get Broker / ClientConnection函数找到一个更通用的名称,让它们在IAdapter
中已经是纯虚拟的,并且在两个实现的适配器类中覆盖它们,所以你然后可以拨打adapter->setXYZ("ampq");
。 [编辑:根据你对问题的评论,而不是给定案例中的选项]
我个人最喜欢的是为createList
函数提供一个额外的参数,以便在工厂内调用setter - 可能使用适当的默认值:空字符串,如果您选择std::string
参数,nullptr
,char const*
。如果参数与默认值不匹配,你只需要调用setter,当然......或者,你可以有两个重载。