Рефакторинг if-цепей в Smalltalk без взрыва класса
Поскольку Smalltalk не рекомендует использовать caseOf:, какие существуют альтернативы для реализации следующей ситуации без взрыва класса?
self condition1
ifTrue: [ self actionForCondition1 ]
ifFalse: [
self condition2
ifTrue: [ self actionForCondition2 ]
ifFalse: [
self condition3
ifTrue: [ self actionForCondition3 ]
ifFalse: [ .... ] ] ]
4 ответа
Если вы прокрутите ближе к концу
http://www.desk.org:8080/CampSmalltalk/control%20flow
Вы найдете предложение
"Есть четыре способа выразить ситуацию в Smalltalk".
следуют ссылки на примеры.
Текст находится в середине немного более длинной серии страниц и дает временные ссылки на гипотетического наставника и студентов на курсе Smalltalk в целях иллюстрации; Вы можете игнорировать это для целей вашего вопроса)
Зависит от того, как точно выглядят ваши условия?
Если ваши условия типовые испытания
anObject isKindOf: aClass
вместо этого вы можете отправлять данные в классе, это означает, что вы вызываете метод действия для
anObject
,Если ваши условия являются тестами на равенство
anObject = anotherObject
Вы можете использовать словарь с объектом в качестве ключа и действием в качестве закрытия блока.
В качестве последнего шага и, если больше ничего не поможет, вы можете переписать предложенный код, чтобы избежать ненужного вложения:
self condition1 ifTrue: [ ^ self actionForCondition1 ]. self condition2 ifTrue: [ ^ self actionForCondition2 ]. self condition3 ifTrue: [ ^ self actionForCondition3 ]. ...
Я думаю, что в тот момент, когда вам приходится писать этот код, я спрашиваю себя, почему я должен написать так много условий, чтобы перейти к следующему шагу в моем алгоритме. Может быть, пришло время подумать, что не так с моделью? Особенно, если вы считаете, что семантика поиска сообщений на самом деле является оператором case:
selector = selector1 ifTrue: [ invoke method1 ]
ifFalse: [ selector= selector2 ifTrue: [ invoke method2 ]
ifFalse: [...] ]]].
Таким образом, вы должны попытаться превратить это в свое преимущество - используйте оператор switch VM вместо написания собственного.
Применяя простой принцип: не спрашивайте (объект isSomething ifTrue:[ self doSomething ]), но говорите (object doSomething), вы можете избежать появления множества ветвей в коде. Конечно, иногда это не применимо и сильно зависит от ситуации, но я часто предпочитаю иметь дополнительную рассылку сообщений, а не другую ветку в коде.
Вы должны взглянуть на двойную диспетчеризацию. В зависимости от того, как реализованы тесты и действия, вы можете использовать двойную диспетчеризацию с большим преимуществом.
Вы хотите получить код, который выглядит следующим образом:
Самостоятельное выполнение действия.
или же
Самостоятельное действиеДействие Выполнение: действие Args
Метод #conditionAction должен будет возвращать уникальный экземпляр объекта для каждого уникального условия (без использования самих операторов case:).
Вы не хотели бы форсировать проблему, создавая классы просто для того, чтобы избежать "операторов case", но в реальном мире у вас уже могут быть некоторые уникальные классы, которые вы можете использовать.