#if-statement #refactoring #smalltalk
#оператор if #рефакторинг #smalltalk
Вопрос:
Поскольку Smalltalk не рекомендует использовать caseOf: , какие существуют альтернативы для реализации следующей ситуации без взрыва класса?
self condition1
ifTrue: [ self actionForCondition1 ]
ifFalse: [
self condition2
ifTrue: [ self actionForCondition2 ]
ifFalse: [
self condition3
ifTrue: [ self actionForCondition3 ]
ifFalse: [ .... ] ] ]
Ответ №1:
Зависит от того, как именно выглядят ваши условия?
-
Если ваши условия являются тестами типа
anObject isKindOf: aClass
вместо этого вы можете отправлять в классе, это означает, что вы вызываете метод action в
anObject
. -
Если ваши условия являются тестами на равенство
anObject = anotherObject
вы можете использовать словарь с объектом в качестве ключа и действием в качестве закрытия блока.
-
В качестве последнего восстановления, и если больше ничего не помогает, вы можете захотеть переписать предлагаемый код, чтобы избежать ненужной вложенности:
self condition1 ifTrue: [ ^ self actionForCondition1 ]. self condition2 ifTrue: [ ^ self actionForCondition2 ]. self condition3 ifTrue: [ ^ self actionForCondition3 ]. ...
Комментарии:
1. 1. Это последнее средство функционально идентично «не рекомендуется»
#caseOf:
.
Ответ №2:
Если вы прокрутите до конца
http://www.desk.org:8080/CampSmalltalk/control flow
вы найдете предложение
«Есть четыре способа выразить оператор case в Smalltalk».
далее следуют ссылки на примеры.
Текст находится в середине немного более длинной серии страниц и содержит случайные ссылки на гипотетического преподавателя и студентов в курсе Smalltalk в целях иллюстрации; вы можете проигнорировать это для целей вашего вопроса)
Ответ №3:
Я думаю, в тот момент, когда вам нужно написать этот код, я бы спросил себя, почему я должен писать так много условий, чтобы продолжить выполнение одного шага в моем алгоритме. Может быть, пришло время подумать, что не так с model? Особенно, если учесть, что семантика поиска сообщений на самом деле является оператором case:
selector = selector1 ifTrue: [ invoke method1 ]
ifFalse: [ selector= selector2 ifTrue: [ invoke method2 ]
ifFalse: [...] ]]].
Итак, вы должны попытаться превратить это в свое преимущество — используйте оператор switch виртуальной машины вместо написания собственного.
Применяя простой принцип: не спрашивать (object IsSomething ifTrue:[ self doSomething ]), а сообщать (object doSomething), вы можете избежать большого количества ветвей в коде. Конечно, иногда это неприменимо и сильно зависит от ситуации, но я часто предпочитаю иметь дополнительную отправку сообщений, а не другую ветвь в коде.
Ответ №4:
Вам следует взглянуть на двойную отправку. В зависимости от того, как реализованы тесты и действия, вы можете использовать двойную отправку с большим преимуществом.
В конечном итоге вы хотите получить код, который выглядит следующим образом:
выполнение действия с самообусловлением.
или
выполнение самодостаточного действия: actionArgs
Метод #conditionAction должен был бы возвращать уникальный экземпляр объекта для каждого уникального условия (без использования самих операторов case :).
Вы бы не хотели усугублять проблему, создавая классы только для того, чтобы избежать «операторов case», но в реальном мире у вас уже может быть несколько уникальных классов, которые вы можете использовать.