通过工厂方法的对象实例化没有给出期望的结果

Object instantiation through factory method not giving desire result

在下面的代码片段中,我确实需要通过工厂方法实例化对象以调用选定的适配器(即 adapterTwovalue),但是在通过工厂方法调用时我无法获得所需的结果。当我们分配静态声明对象的地址(即 adapter = &at)时,它可以工作,但对于工厂,我通常会得到空白输出。 我也尝试使用 (adapter = new adapterTwo()) 实例化对象,但输出字符串给出空白结果。根据我的要求,我需要填充 connect 函数中的所有 getter,这是纯虚函数来构建 response.Anybody 可以建议如何使用工厂方法实现此目的。

    #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;
    }

使用您的代码,我希望输出:final value=

它不会打印 final value=amqp 因为您需要在正确的适配器对象上调用 SetClientbroker("amqp")(在您的示例中为 adapter)。

无论如何,我会考虑在基础 class 中放置一个虚拟方法 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 所建议)。 但恕我直言,它一点也不优雅。我认为您将失去使用工厂方法获得的好处。

IAdapter* adapter = nullptr;
AdapterTwo at;
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);

您在这里创建了两个 independent 对象(在 createList 中调用 new):at 和一个 adapter 指向.

AdapterTwo at;
at.SetClientbroker("amqp");

现在,如果让 adapter 指向 at,您肯定会得到预期的输出,但是 other 对象怎么会知道您输入的字符串设置在第一个?

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

仅:标记的行 ((*)) 不会 编译,因为您的基础 class 没有提供适当的 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 函数找到一个更通用的名称,让它们在 IAdapteroverride 中已经是纯虚拟的在两个实现适配器 classes 中,这样您就可以调用 adapter->setXYZ("ampq");[编辑:根据您对问题的评论,在给定的情况下不是一个选项]

我个人最喜欢的是为您的 createList 函数提供一个额外的参数,这样 setter 就已经在工厂内被调用了——可能有适当的默认值:空字符串,如果您选择一个std::string 参数,或 nullptrchar const* 的情况下。如果参数与默认值不匹配,你只会调用 setter,当然......或者,你可以有两个重载。

您可以在下面的分享中看到完整的解决方案link。

http://coliru.stacked-crooked.com/a/d8b9d32a1fa989c9

这里是解释。

(1) setClientBroker() 或所有其他与适配器相关的 setter 功能需要在具有默认参数值“ ”(空白字符串)的接口中实现为虚函数。

(2) 您需要始终在派生 class 中为 setter 使用覆盖关键字 (c++11) 功能,以便编译器在编译期间交叉检查是否正在使用正确的虚拟方法是否覆盖。

(3) 不要使用本地原始指针,总是使用智能指针。下面是 实现 link 相同。

http://coliru.stacked-crooked.com/a/2feea991ee90d4a2