Реализация объекта через фабричный метод не дает желаемого результата - PullRequest
0 голосов
/ 06 июня 2018

В приведенном ниже фрагменте кода мне требуется создать экземпляр объекта с помощью фабричного метода, чтобы вызвать выбранный адаптер (т. Е. adapterTwovalue), но при вызове с помощью фабричного метода я не могу получить желаемые результаты.Когда мы назначаем статический объявленный адрес объекта (то есть adapter = &at), он работает, но с фабрикой я обычно получаю пустой вывод.Я также пытался с помощью (adapter = new adapterTwo()) создать экземпляр объекта, но выходная строка дает пустые результаты.Согласно моему требованию, мне нужно заполнить все геттеры в функции connect, которая является чисто виртуальной функцией для формирования ответа. Любой может подсказать, как этого добиться, используя фабричный метод.

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

Ответы [ 3 ]

0 голосов
/ 06 июня 2018
IAdapter* adapter = nullptr;
AdapterTwo at;
adapter = IAdapter::CreateList(IAdapter::AdapterTwovalue);

Вы создали два независимых объекта здесь (как при вызове new в createList): at, а один adapter указывает на.

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

Only: Theотмеченные линии ((*)) не будут компилироваться, поскольку ваш базовый класс не предоставляет соответствующий установщик!

В настоящее время существуют различные решения этой проблемы.Например, вы можете просто привести объект:

// 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Функция такова, что сеттер уже будет вызываться внутри фабрики - возможно, с соответствующим значением по умолчанию: пустая строка, если вы выберете параметр std::string, или nullptr в случае char const*.Разумеется, вы вызываете сеттер только в том случае, если параметр не соответствует значению по умолчанию ... Как вариант, вы можете иметь две перегрузки.

0 голосов
/ 06 июня 2018

Вы можете увидеть полное решение по ссылке ниже.

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

Вот объяснение.

(1) setClientBroker () или все другие связанные с адаптерами функциональные возможности сеттера должны быть реализованы как виртуальная функция в интерфейсе со значением параметра по умолчанию "" (пустая строка).

(2) вам необходимовсегда используйте функцию переопределения ключевого слова (c ++ 11) в производном классе для сеттеров, чтобы во время компиляции компилятор перепроверял, переопределен ли правильный виртуальный метод.

(3) вместо использования локального необработанного указателя,всегда используйте умный указатель.ниже приведена ссылка для реализации того же.

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

0 голосов
/ 06 июня 2018

С вашим кодом я ожидаю вывод: 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).Но имхо это совсем не элегантно.Я думаю, что вы потеряете преимущества, полученные фабричным методом.

...