Сегодня я получил обзор кода от старшего разработчика, спрашивающего: «Кстати, что ты возражаешь против диспетчеризации функций с помощью оператора switch?» Во многих местах я читал о том, что перекачивание аргумента через метод switch для вызова методов является плохим ООП, не настолько расширяемым и т. Д. Однако я не могу придумать для него однозначного ответа. Я хотел бы решить это для себя раз и навсегда.
Вот наши конкурирующие предложения кода (php используется в качестве примера, но может применяться более универсально):
class Switch {
public function go($arg) {
switch ($arg) {
case "one":
echo "one\n";
break;
case "two":
echo "two\n";
break;
case "three":
echo "three\n";
break;
default:
throw new Exception("Unknown call: $arg");
break;
}
}
}
class Oop {
public function go_one() {
echo "one\n";
}
public function go_two() {
echo "two\n";
}
public function go_three() {
echo "three\n";
}
public function __call($_, $__) {
throw new Exception("Unknown call $_ with arguments: " . print_r($__, true));
}
}
Часть его аргумента звучала так: «Он (метод switch) имеет гораздо более чистый способ обработки случаев по умолчанию, чем тот, который вы используете в общем магическом методе __call ()».
Я не согласен с чистотой и на самом деле предпочитаю звонить, но я хотел бы услышать, что говорят другие.
Аргументы, которые я могу привести в поддержку Oop
схемы:
- Немного чище с точки зрения кода, который вы должны написать (меньше, легче читать, меньше ключевых слов для рассмотрения)
- Не все действия делегируются одному методу. Здесь нет большой разницы в исполнении, но, по крайней мере, текст более разделен.
- В том же духе, другой метод может быть добавлен в любом месте класса вместо определенного места.
- Методы пространства имен, что приятно.
- Здесь не применимо, но рассмотрим случай, когда
Switch::go()
оперируется членом, а не параметром. Сначала вам нужно изменить член, а затем вызвать метод. ИбоOop
вы можете вызывать методы самостоятельно в любое время.
Аргументы, которые я могу привести в поддержку Switch
схемы:
- Ради аргумента, более чистый метод работы с запросом по умолчанию (неизвестно)
- Кажется менее волшебным, что может заставить незнакомых разработчиков чувствовать себя более комфортно
Кому-нибудь есть что добавить для любой из сторон? Я хотел бы получить хороший ответ для него.
источник
Oop
позволяет иметь phpdoc для описания каждого метода, который может быть проанализирован некоторыми IDE (например, NetBeans).Ответы:
Переключатель считается не ООП, потому что часто полиморфизм может помочь.
В вашем случае реализация ООП может быть такой:
источник
для этого примера:
ОК, только частично шучу здесь. Аргумент за / против использования оператора switch нельзя убедительно привести в таком тривиальном примере, поскольку сторона ООП зависит от используемой семантики, а не только от механизма диспетчеризации .
Операторы Switch часто указывают на отсутствующие классы или классификации, но не обязательно. Иногда оператор switch является просто оператором switch .
источник
Возможно, не ответ, но в случае кода без переключения, кажется, что это было бы лучшим соответствием:
Большая часть головоломки для оценки - это то, что происходит, когда вам нужно создать
NewSwitch
илиNewOop
. Ваши программисты должны прыгать через обручи тем или иным способом? Что происходит при изменении ваших правил и т. Д.источник
is_callable
, но оставил call_user_func, так как (не часть этого вопроса), могут быть другие аргументы для передачи. Но теперь, когда это перешло к программистам, я определенно согласен с тем, что @ Андреа ответ гораздо лучше :)Вместо того, чтобы просто помещать исполняемый код в функции, реализуйте полный шаблон команды и поместите каждый из них в свой собственный класс, который реализует общий интерфейс. Этот метод позволяет вам использовать IOC / DI для соединения различных «падежей» вашего класса и позволяет легко добавлять и удалять наблюдения из вашего кода с течением времени. Это также дает вам хороший код, который не нарушает принципы программирования SOLID.
источник
Я думаю, что пример плохой. Если есть функция go (), которая принимает аргумент $ where, если совершенно правильно использовать switch в функции. Наличие единственной функции go () облегчает изменение поведения всех go_where () в зависимости от ситуации. Кроме того, вы сохраните интерфейс класса - если вы используете различные методы, вы изменяете интерфейс класса с каждым новым назначением.
На самом деле ключ должен быть заменен не набором методов, а набором классов - это полиморфизм. Тогда назначение будет обрабатываться каждым подклассом, и для всех них будет один метод go (). Замена условного полиморфизма является одним из основных рефакторингов, описанных Мартином Фаулером. Но вам может не понадобиться полиморфизм, и переход - это путь.
источник
go()
это может легко нарушить принцип подстановки Лискова. Если вы хотите добавить больше функциональных возможностейgo()
, вы действительно хотите изменить интерфейс, насколько я concerend.