Замена switch-case полиморфизмом
В прекрасной книге "Философия С++" Брюса Эккеля я прочитал рекомендацию о том, что не следует использовать длинные switch-case конструкции. Вместо этого нужно применять полиморфизм и наследование. Вот убейте меня на месте, но я не пойму, как одно можно заменить другим!
Что такое switch-case конструкция? Это реализация выбора некоторого кода (из имеющегося списка) в соответствии с некоторым однозначно интерпретируемым критерием. Когда мы имеем дело с полиморфными вызовами функций классов наследников, используя при этом общий интерфейс (то есть класс-родитель), то здесь тоже наблюдается идея выбора кода (например, переопределенной функции) из некоторого множества. Но ведь в switch-case конструкции критерием является значение некоторой переменной (так чаще всего), а в случае с полиморфизмом критерием является тип!
Может быть, я, будучи новичком в С++, чего-то просто не понимаю? Не могли бы вы привести хотя бы примитивные примеры, как можно заменить первое вторым. Буду очень признателен.
http://forum.exler.ru/index.php?showtopic=115776 и ссылки в ответах посотреть
Поглядите книжечку Стефана Дэвиса "С++ for Dumies", там хорошо и доступным языком расписано, что такое объекты и принципы ООП подхода и их различия между функциональным программирование.
[/LEFT]
Что такое объекты и принципы ООП, мне известно. И хотя я начинающий в языке, но уже, в принципе, не чайник. Вот вы заменяли когда-нибудь switch-case конструкцию на полиморфные вызовы функций-наследников от базового интерфейса? Если да, то буду признателен за ваши примеры. Коротко, прямо здесь, на форуме.
Я вобще очень редко (если опять таки честно) применяю конструкции case, считаю что возможно обойтись и без них, думаю эта конструкция хоть и используется в С++, но всё же(это моё мнение) она изжила себя и просто мигрировала из С))))
Я больше как-то использую Java...хм...и сами подумайте..ведь в Java как-то люди обходятся без case))))
[/LEFT]
Я больше как-то использую Java...хм...и сами подумайте..ведь в Java как-то люди обходятся без case))))
=)))))))))))
Ты что этим хотел сказать, что в Java нет конструкции switch/case абсолютно такой же как и в C/C++?
Ты что этим хотел сказать, что в Java нет конструкции switch/case абсолютно такой же как и в C/C++?
Я лично хотел сказать что она нафиг не нужна, вот и всё (это чисто по Русски)))). Блин, aks не придерайся к словам, а....
Или ты видел код на Java перенасыщенный конструкциями switch/case????
Продемонстрируй плиз))))) Очень хочу поглядеть :)
[/LEFT]
=))
И вот тебе простой пример - как ты будешь например определять тип пакета приходящего из какого то внешнего источника (сети, файла, или еще откуд - неважно) у которого тип как раз задается допустим константой идущей в первом байте?
И вот тебе простой пример - как ты будешь например определять тип пакета приходящего из какого то внешнего источника (сети, файла, или еще откуд - неважно) у которого тип как раз задается допустим константой идущей в первом байте?
Интересный пример... чтоб показать один из вариантов замены switch/case полиморфизмом. :)
При небольшом количестве вариантов пакетов и нерасширяемой архитектуре switch/case будет вполне нормальным решением.
Но для других случаев больше подойдет архитектура с регистрацией обработчиков (псевдокод):
{
TypeID getID() const =0;
TypeResult handlePacket(cont Packet&) =0;
};
class DataPacketHandler :IPacketHandler
{
TypeID getID() const { return dataPacketID; }
TypeResult handlePacket(cont Packet&);
};
class CommandPacketHandler :IPacketHandler
{
TypeID getID() const { return commandPacketID; }
TypeResult handlePacket(cont Packet&);
};
class PacketManager
{
void addPacketHandler(IPacketHandler* handler) {
handlers.add(handler);
}
TypeResult handlePacket(cont Packet& packet) {
for_each(handlers) {
if( handler->getID() == packet.id ) {
return handler.handlePacket(packet);
}
}
}
Container<IPacketHandler*> handlers;
};
В таких случаях любят делать авторегистрацию, и даже автосоздание обработчика, но я сторонник явного создания и регистрации.
Но все же когда количество типов строго фиксированное и небольшое то зачастую прощще через switch создавть объект необходимого типа.
Это чем же?? Интерфейс требует организации новой структуры, тогда как функцию можно просто передать по ссылке.
По большому счету это паттерн "стратегия". Каждая стратегия - отдельная сущность, которую целесообразнее оформлять в отдельный класс.
Ну и расширяемая вешь получается. Можно объединять несколько методов в одном таком классе-обработчике, например, предобработка и пост обработка (я недавно выкладывал HookAPI, там это явно прослеживается), можно хранить состояние обработчика и т.д. Представляется возможность получать информацию об обработчиках, настраивать их. Это нужно для более интеллектуальных менеджеров, например, кодеки: каждый кодек не только обрабатывает поток входных данных, но может и давать информацию о себе об формате входных и выходных данных. Это нужно, к примеру, для построения графов таких кодеков (см. DirectShow и GraphEdit).
Кроме того, засовывать всю обработку в одну функцию на несколько десятков страниц - плохая практика. Разбивать функцию на несколько и плодить при этом глобальные функции - тоже некрасиво. А так есть некоторый класс-обработчик, с четкой самостоятельной структурой и общим интерфейсом. От которого, кстати, можно наследовать другие обработчики.
В принципе вопрос из серии: что лучше callback-функция или объект-обработчик?
Вот вот...это точно...
Я бы сказал это ещё дело "вкуса" aks и кто какую "стратегию" выбрал для себя. Я всё же бы заменил switch/case , на if/else if/else (ну привык я так). Например, уже давно читал книжечку Дениса Ричи "Язык Си", он там аргументирует (не помню правда агрументов), почему лично он заменяет switch/case на if-else, но так же пишет о "привычке" к такому решению лично его самого. А в других случаях, работа только с объектами и обработчиками при принятия данных в твоём примере. А за ссылочку спасибо, внушает)))
[/LEFT]