Russian Qt Forum
Ноябрь 22, 2024, 23:35 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: Большой switch  (Прочитано 14696 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Декабрь 24, 2014, 09:24 »

Добрый день

Есть баааальшой switch

Код
C++ (Qt)
void CopyParam( MyClass & dst, const MyClass & src, int id )
{
switch (id) {
  case ID_ENABLED:
    if (dst.mEnabled != src.mEnabled) {
      SaveUndo(dst);
      dst.mEnabled = src.mEnabled;
      UpdateUI();
    }
    break;
 
  case ID_COUNT:
    if (dst.mCount != src.mCount) {
      SaveUndo(dst);
      dst.mCount = src.mCount;
      UpdateUI();
    }
    break;
   ...
// и так еще много-много раз
}
Есть ли что-то лучшее?

Спасибо
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Декабрь 24, 2014, 09:26 »

Кот везде одинаковый, за исключением проверяемого поля? Я правильно понял?
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #2 : Декабрь 24, 2014, 09:32 »

С первого приближения, можно часть кода вынести в шаблон.
Код
C++ (Qt)
template<class T, class M>
void work (const T &dest, M &destMember, const M &sourceMember)
{
 if (destMember != sourceMember) {
   SaveUndo(dest);
   destMember = sourceMember;
   UpbateUI();
 }
}
 
switch(id) {
 case ID_ENABLED:
   work(dst, dst.mEnabled, src.mEnabled);
   break;
.....
}
 
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Декабрь 24, 2014, 10:00 »

С первого приближения, можно часть кода вынести в шаблон.
Именно так я и сделал Улыбающийся  Но

1) От switch это все-таки не избавляет (хотя значительно сокращает)

2) Код "не везде одинаковый". Да, в половине случаев из 100 - все одинаково как выше. В других напр UpdateUI не нужно. В других (еще более редких) нужно еще доп действие(я).

Можно "продолжать в том же духе", напр
Код
C++ (Qt)
void work (const T &dest, M &destMember, const M &sourceMember, bool updateUI = false, bool action1 = false........)
Но это не очень удобно вызывать
Код
C++ (Qt)
worj(dst, dst.mCount, src.mCount, false, true, false);
Как часто бывает, bool нехороший аргумент для вызывающего. Придется рисовать enum'ы. И как-то это все "распухает", дорисовать нужное в switch выглядит проще

Да, и радость с темплейт здесь возможна т.к. все члены public (как и есть в этом старом коде). Но ведь "грамотно" все через геттеры/сеттеры
Код
C++ (Qt)
int MyClass::count( void ) const { return count; }
void MyClass::setCount( int cnt ) { count = cnt; }
 
И как тогда?  Улыбающийся
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #4 : Декабрь 24, 2014, 10:09 »

Если ты обернешь мемберов в геттер/сеттер, то можно забабахать через паттерн стратеггия.
Код
C++ (Qt)
class AbstractStrategy
{
   virtual bool canDo(int id) const = 0;
   virtual void do(MyClass & dst, const MyClass & src) = 0;
}
 

Далее делаешь стратегии, заточенные на нужные геттеры/сеттеры и необходимые действия и помещаешь их в фабрику. Твой свитч превращается в запрос у фабрики нужной стратегии и выполнения у нее do. Кода будет больше, зато очень легко можно будет расширять и понятнее кот станет.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #5 : Декабрь 24, 2014, 10:12 »

Даже без геттеров/сеттеров можно, но тогда больше классов получится. Если юзать геттеры/сеттеры, можно создать меньше стратегий, передавая в конструктор std::function и инициализируя их в фабрике с передачей ссылок на нужные методы.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
sergek
Гипер активный житель
*****
Online Online

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #6 : Декабрь 24, 2014, 12:52 »

Можно switch заменить Mapом.
В MyClass определяете много-много методов с сигнатурой что-то вроде MyClass::copy_тип_проверки(const MyClass & src, int id), ассоциативный массив типа QMap<int, MyClass::*тип_функции> и один метод copyParam с такой-же сигнатурой.
В конструкторе один раз заполняете массив, например, massiv[ID_ENABLED] = &MyClass::copy_ENABLED.
Все методы, кроме copyParam - закрытые. Метод copyParam находит в массиве нужную функцию и передает ей параметры. В общем и все.
Кода меньше не станет, но все можно попрятать в private секцию, и вся реализация - в классе, а не где-то в коде.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #7 : Декабрь 24, 2014, 13:03 »

sergek, а куда засунешь вызовы SaveUndo и UpdateUI?
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
sergek
Гипер активный житель
*****
Online Online

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #8 : Декабрь 24, 2014, 13:16 »

Я могу только посоветовать, куда Подмигивающий Сам туда не хочу.
Функции глобальные - какие проблемы?
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Декабрь 24, 2014, 13:25 »

Кода меньше не станет, но все можно попрятать в private секцию, и вся реализация - в классе, а не где-то в коде.
Я понял, но ф-ция копирования не особо лепится внутри класса, т.к. он должен знать про SaveUndo, UpdateUI и др - а это к нему отношения не имеет.

Не то чтобы я прямо-таки несчастен со switch'ом, ничего страшного нет, пополнять/изменять легко. Просто у меня много такого старого кода, вот и прикидываю как бы (может быть) модернизировать.

Если ты обернешь мемберов в геттер/сеттер, то можно забабахать через паттерн стратеггия.
Код
C++ (Qt)
class AbstractStrategy
{
   virtual bool canDo(int id) const = 0;
   virtual void do(MyClass & dst, const MyClass & src) = 0;
}
 

Далее делаешь стратегии, заточенные на нужные геттеры/сеттеры и необходимые действия и помещаешь их в фабрику. Твой свитч превращается в запрос у фабрики нужной стратегии и выполнения у нее do. Кода будет больше, зато очень легко можно будет расширять и понятнее кот станет.
Ничего не понял  Плачущий. Можно расширить Ваш псевдокод? Придираться не буду Улыбающийся Да, и если можно - хоть как-то осмысленное имя вместо "do", а то я совсем растерялся.

Спасибо
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #10 : Декабрь 24, 2014, 14:14 »

Совсем псевдокодный псевдокот.
Код
C++ (Qt)
class BoolMethodStrategy : public AbstractStrategy
{
public:
  BoolMethodStrategy(std::function<bool(MyClass*)> getMethod, std::function<void(MyClass*, bool val)> setMethod);
  virtual void copy(MyClass & dst, const MyClass & src) {
     if (getMethod_(&dst) != getMethod_(&src)............
  }
}
 
....................
map[1] = new BoolMethodStrategy(&MyClass::enabled, &MyClass::setEnabled)
 
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #11 : Декабрь 24, 2014, 21:43 »

Добрый день
Есть баааальшой switch
Есть ли что-то лучшее?

Альтернатива свитчу - полиморфизм.

Известно, что простой свитч (даже если он оч длинный стал с годами) предпочтительнее, чем ооп головного мозга.

Не рекомендую рассматривать вам выше приведенные примеры для практического использования.

модель ооп должна быть очень простой, или она не имеет смысла.
так же, она не должна создавать прецедент падению производительности (использование медленных new и прочее)
Записан
Akon
Гость
« Ответ #12 : Декабрь 25, 2014, 03:32 »

Код:
class MyClass
{
public:
MyClass(bool enabled, int count) : enabled(enabled), count(count) {}

bool enabled;
int count;
};

/// Field IDs
static const int ID_ENABLED = 0;
static const int ID_COUNT = 1;

/// Primary class template and its specializations to map field Id to field pointer
template <int Id> struct MemberById;
template <> struct MemberById<ID_ENABLED> { static constexpr auto Member = &MyClass::enabled; };
template <> struct MemberById<ID_COUNT> { static constexpr auto Member = &MyClass::count; };
...

template <int Id>
void CopyParam(MyClass& dst, const MyClass& src)
{
auto& dstMember = dst.*MemberById<Id>::Member;
const auto& srcMember = src.*MemberById<Id>::Member;

if (dstMember != srcMember) {
SaveUndo(dst);
dstMember = srcMember;
UpdateUI();
}
}


Usage:
MyClass src(false, 0);
MyClass dst(true, 1);

CopyParam<ID_ENABLED>(dst, src);
CopyParam<2>(dst, src);  // compile-time error: 2 is not covered

Это идея sergek со след. отличиями:
1. весь маппинг производится в компайл-тайм (нет прецедентов падению производительности);
2. маппится не операция над конкретными полями, а смещения полей. Напр. возможно такое:
auto sum = dst.*MemberById<ID_COUNT>::Member + src.*MemberById<ID_COUNT>::Member.

Использование геттеров/сеттеров принципиальности не вносит - указателю на член будет соответствовать пара указателей на функции-члены.

В Qt подобного рода задачи решаются через MetaTypes (напр.  QObject::property()/setProperty(), где ключом выступает имя св-ва).

OOP головного мозга - это ерунда по сравнению с TMP (template metaprogramming) оного. А вообще самый быстрый вариант - это С-макро... и, зачастую, кто не брезгует, тот впереди Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Декабрь 25, 2014, 09:53 »

Известно, что простой свитч (даже если он оч длинный стал с годами) предпочтительнее, чем ооп головного мозга.
Это старый код писаный др программистом где-то в начале 90-х. Иногда заметно что он переводился с паскаля  Улыбающийся Первое впечатление аховое ("о боже как примитивно!!" и.т.п.), но предложить что-то лучшее совсем непросто, во всяком случае мне это пока не удалось. Ну я особо и не рвусь, просто обдумываю.

С паттерном "стратегия" что-то совсем мрачно. Код заметно усложнился для понимания, а достигнуто лишь присваивание члена. Впрочем я никогда не понимал этих "паттернов"

Код:
template <int Id> struct MemberById;
template <> struct MemberById<ID_ENABLED> { static constexpr auto Member = &MyClass::enabled; };
Идею знал (темплейт "по числу"), но оформить бы так не сумел. Спасибо
Хорошо, теперь мы можем присваивать члены класса по id. Но пробежаться циклом (вместо switch) все равно не удается, напр
Код
C++ (Qt)
const iint id[] = { ID_ENABLED, ID_COUNT, ... };
for (int i = 0; i = sizeof(id) / sizeof(int); ++i)
CopyParam <???>   // но ведь нельзя подставить i
 
Хотя даже если бы и можно - все равно недостаточно. Т.к. не все ветки switch одинаковы, (хотя повторов очень иного). А CopyParam да, значение присвоит, но эти доп действия не выполнит
Записан
Bepec
Гость
« Ответ #14 : Декабрь 25, 2014, 10:43 »

switch простейший паттерн множественного ветвления. И как вы не старайтесь у вас в результате получится тот же switch только более сложный по реализации Веселый

PS на мой взгляд очередная провокация Igors "А давайте сделаем молоток ещё лучше - с пилкой по металлу на другом конце рукояти" Веселый
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.321 секунд. Запросов: 22.