как лучше сделать
От: sergey2b ЮАР  
Дата: 23.02.20 20:00
Оценка:
есть базовый асбрактный класс
от него наследуеться N классов, каждый из которых с своими особенностями
есть фабрика которая возращает поинтер на объект нужного класса в заисимости от настроек

один из классов был мной с оптимизирован и все хорошо, но теперь в него надо передать несколько опций (значения INT)

как по фуншую сделать передачу опций

1) изменить базовый класс и добавить методы getOption setOption но остальный классам они не нужны и работаю только с одним проектом а как я понял этот класс исполььзуеться и в других проетках

2) добавить в нужный мне класс новый методы но тогда интерефейс этого класса будет отличаеться от остальный родственных классов

3) у класса есть метод setup но в нем передаеться только путь к файлу который этот класс будет обрабатывать
можно через эту строку передавать опции и внутри парсить
выглядит убого но все изменения затронут только один нужный мне класс


как лучше сделать добавление новых методов getOption setOption
Re: как лучше сделать
От: rg45 СССР  
Дата: 23.02.20 20:15
Оценка: +1
Здравствуйте, sergey2b, Вы писали:

S>есть базовый асбрактный класс

S>от него наследуеться N классов, каждый из которых с своими особенностями
S>есть фабрика которая возращает поинтер на объект нужного класса в заисимости от настроек

S>один из классов был мной с оптимизирован и все хорошо, но теперь в него надо передать несколько опций (значения INT)



Я не уверен, что правильно понял задачу. Фабричный метод не может передать все эти дополнительные опции создаваемому объекту через конструктор?
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 25.02.2020 11:16 rg45 . Предыдущая версия .
Re: как лучше сделать
От: okon  
Дата: 23.02.20 20:29
Оценка: 6 (1)
S>2) добавить в нужный мне класс новый методы но тогда интерефейс этого класса будет отличаеться от остальный родственных классов

А это разве плохо, у тебя главное не меняется основной интерфейс например


public interface IFigure
{
   double GetSquare();
}

public class Rectangle : IFigure
{
   public double Width {get;set;}
   public double Height {get;set;}
   public double GetSquare();
}

public class Circle : IFigure
{
   public double Radius {get;set;}
   public double GetSquare();
}


Это вполне нормально что имплементация разная и имеет разные свойства.

Инициализировать можно их по разному :

1. Непосредственно через конструктор
2. Присваивать через свойства/методы там где создается экземпляр
3. Если много кода для инициализации где можно вынести логические блоки, то иногда лучше сделать Builder, чтобы понятнее был код
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 23.02.2020 20:30 okon . Предыдущая версия . Еще …
Отредактировано 23.02.2020 20:30 okon . Предыдущая версия .
Re[2]: как лучше сделать
От: sergey2b ЮАР  
Дата: 23.02.20 20:33
Оценка:
Здравствуйте, rg45, Вы писали:


R>Я не уверен, что правильно понял задачу. Фабричный метод не может передать все эти дополнительные опции создаваемому объекту через конструктор?


да может
это один вариантов
Re[3]: как лучше сделать
От: rg45 СССР  
Дата: 23.02.20 20:34
Оценка: 6 (1) +4
Здравствуйте, sergey2b, Вы писали:

R>>Я не уверен, что правильно понял задачу. Фабричный метод не может передать все эти дополнительные опции создаваемому объекту через конструктор?


S>да может

S>это один вариантов

Тогда я отдаю свой голос за этот вариант
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: как лучше сделать
От: Erop Россия  
Дата: 26.02.20 09:56
Оценка: 12 (1)
Здравствуйте, sergey2b, Вы писали:

S>3) у класса есть метод setup но в нем передаеться только путь к файлу который этот класс будет обрабатывать

S>можно через эту строку передавать опции и внутри парсить
S>выглядит убого но все изменения затронут только один нужный мне класс


S>как лучше сделать добавление новых методов getOption setOption


1) Если во время существования объекта не надо иметь доступ к доп. параметрам, то мне тоже нравится решение от
rg45

2) Если же всё-таки нужны именно методы getOption setOption (например, есть какие-то версии доп. параметров для некоторых объектов и мы пробуем применять то одни, то другие), то можно пойти по python/smalltalk-style пути и передавать либо имя/ID доп. опции в методы getOption setOption БАЗЫ
либо std::map<std::string, int>
Но неудобно то, что динамики многовато для С++ и то, что если в разных классах понадобятся разные типы, то будет неудобно.
Хотя разные типы обеспечить более или менее можно

3) Завести структуру/класс ExtraOptions с виртуальным деструктором. Для тех классов, кому надо, выводить из неё расширенные версии.
В метод setOption передавать ссылку на такую структуру, а в методе класса dyn_cast'ом кастить вниз и получать доступ туда, куда нужно
А из getOption сразу возвращать выведенную структуру.

https://www.ideone.com/e7bQ52
  "Вот пруф оф концепт: "
#include <iostream>
#include <string>
#include <map>
#include <assert.h>

struct IObj {
    //------ Подход 3 ----------------------------------------------
    struct ExtraOptionsBase {
        virtual ~ExtraOptionsBase() {}
    };    
    
    virtual void SetEO( ExtraOptionsBase& ) = 0; // Можно сделдать дефолтную пустую реализацию
    virtual ExtraOptionsBase& GetEO() = 0;

    //------ Подход 2 ----------------------------------------------
    virtual bool SetOption( const std::string& name, const int& value )  { return false; }
    virtual bool TryGetOption( const std::string& name, int& value ) { return false; }
    virtual bool SetOption( const std::string& name, const std::string& value ) { return false; }
    virtual bool TryGetOption( const std::string& name, std::string& value ) { return false; }
    
    template<typename T> T GetOption( const std::string& name ) {
        T res = T();
        bool is_ok = this->TryGetOption( name, res ); 
        assert( is_ok );
        return res;
    }    
};

template<typename T>
struct CObj : public IObj {
    //------ Подход 3 ----------------------------------------------
    struct ExtraOptions : public IObj::ExtraOptionsBase {
        T Param1;
        T Param2;
        
        T* getField( const std::string& name ) {
            if( name == "Param1" )
                return &this->Param1;
            if( name == "Param2" )
                return &this->Param2;
            return 0;
        }
    } Data;
    
    virtual ExtraOptions& GetEO() { return this->Data; }
    virtual void SetEO( ExtraOptions& ed ) { this->Data = ed; }
    virtual void SetEO( ExtraOptionsBase& ed ) { this->Data = dynamic_cast<ExtraOptions&>(ed); }
    
    //------ Подход 2 ----------------------------------------------
    virtual bool SetOption( const std::string& name, const T& value ) {
        T* field = this->Data.getField( name );
        if( field ) {
            *field = value;
            return true;
        }
        return false;
    }
    
    virtual bool TryGetOption( const std::string& name, T& value ) { 
        T* field = this->Data.getField( name );
        if( field ) {
            value = *field;
            return true;
        }
        return false;
    }
};


using namespace std;

int main() {
    
    std::map<std::string, int> pi = {
        { "Param1", 5 },    
        { "Param2", 10 },    
    };
    CObj<int> oi1, oi2;
    for( auto i = pi.begin(); i != pi.end(); ++i )
        oi1.SetOption( i->first, i->second );
    oi2.SetEO( oi1.GetEO() );
    std::cout << oi2.GetEO().Param1 << " " << oi2.GetOption<int>( "Param2" ) << std::endl;
    
    std::map<std::string, std::string> ps = {
        { "Param1", "Hello" },    
        { "Param2", "world!" },    
    };
    CObj<std::string> os1;
    for( auto i = ps.begin(); i != ps.end(); ++i ) 
        os1.SetOption( i->first, i->second );
    std::cout << os1.GetEO().Param1 << " " << os1.GetOption<std::string>( "Param2" ) << std::endl;

    // your code goes here
    return 0;
}


выдаёт
5 10
Hello world!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Отредактировано 26.02.2020 10:21 Erop . Предыдущая версия .
Re[2]: как лучше сделать
От: rg45 СССР  
Дата: 27.02.20 09:55
Оценка: +1
Здравствуйте, Erop, Вы писали:

E>2) Если же всё-таки нужны именно методы getOption setOption (например, есть какие-то версии доп. параметров для некоторых объектов и мы пробуем применять то одни, то другие), то можно пойти по python/smalltalk-style пути и передавать либо имя/ID доп. опции в методы getOption setOption БАЗЫ

E>либо std::map<std::string, int>
E>Но неудобно то, что динамики многовато для С++ и то, что если в разных классах понадобятся разные типы, то будет неудобно.
E>Хотя разные типы обеспечить более или менее можно

E>3) Завести структуру/класс ExtraOptions с виртуальным деструктором. Для тех классов, кому надо, выводить из неё расширенные версии.

E>В метод setOption передавать ссылку на такую структуру, а в методе класса dyn_cast'ом кастить вниз и получать доступ туда, куда нужно
E>А из getOption сразу возвращать выведенную структуру.

Ну вот я бы воздержался от таких мер, не будучи уверенным, что они действидешьно нужны. И даже если бы столкнулся с тем, что методы getOption и setOption действительно нужны, в первую очередь посмотрел бы, а нельзя ли изменить дизаайн верхнего уровня так, чтобы необходимость в этих методах исчезла. Чем проще инварианты, тем надежнее программа и проще поддержка.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 27.02.2020 10:31 rg45 . Предыдущая версия . Еще …
Отредактировано 27.02.2020 9:55 rg45 . Предыдущая версия .
Re[3]: как лучше сделать
От: Erop Россия  
Дата: 27.02.20 10:24
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Ну вот я бы воздержался от таких мер, не будучи уверенным, что они действидешьно нужны. И даже если бы с толкнулся с тем, что метода getOption и setOption действительно нужны, в первую очередь посмотрел бы, а нельзя ли изменить дизаайн верхнего уровня так, чтобы необходимость в этих методах исчезла. Чем проще инварианты, тем надежнее программа и проще поддержка.


Ну это-то да, но от задачи же зависит. Простой пример. У меня есть какие-то объекты, которые что-то делают, но иногда им надо откатываться к предыдущему состоянию.
Ну вот, если сами объекты полиморфные, и мы ими как-то на высоком уровне рулим, например балансируем нагрузку, то полиморфные или вообще нетипизированные состояния -- вполне так себе выход.
При этом полиморфные, IMHO, лучше тем, что если что-то пойдёт не так -- сломается, а нетипизированные (json, например) тем, что их легче сделать человекочитаемыми.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.