Рефакторинг if-цепей в Smalltalk без взрыва класса - PullRequest
6 голосов
/ 13 ноября 2011

Поскольку Smalltalk не рекомендует использовать caseOf: какие существуют альтернативы для реализации следующей ситуации без взрыва класса?

Ответы [ 4 ]

6 голосов
/ 13 ноября 2011

Зависит от того, как точно выглядят ваши условия?

  • Если ваши условия - это типовые испытания

    anObject isKindOf: aClass
    

    вместо этого вы можете отправить класс, это означает, что вы вызываете метод действия в anObject.

  • Если ваши условия - тесты на равенство

    anObject = anotherObject
    

    Вы можете использовать словарь с объектом в качестве ключа и действием в качестве закрытия блока.

  • В качестве последнего перезапуска и, если ничего не помогает, вы можете переписать предложенный код, чтобы избежать ненужного вложения:

    self condition1
        ifTrue: [ ^ self actionForCondition1 ].
    self condition2
        ifTrue: [ ^ self actionForCondition2 ].
    self condition3
        ifTrue: [ ^ self actionForCondition3 ].
    ...
    
4 голосов
/ 14 ноября 2011

Если вы прокроете ближе к концу

http://www.desk.org:8080/CampSmalltalk/control%20flow

, вы найдете предложение

"Существует четыре способа выражения выражения case в Smalltalk. "

, за которыми следуют ссылки на примеры.

Текст находится в середине немного более длинной серии страниц и иногда дает ссылки на гипотетического репетитора и студентов в курсе Smalltalk в целях иллюстрации;Вы можете игнорировать это для целей вашего вопроса)

2 голосов
/ 14 ноября 2011

Я думаю, что в тот момент, когда вам приходится писать этот код, я спрашиваю себя, почему я должен написать так много условий, чтобы перейти к следующему шагу в моем алгоритме. Может быть, пришло время подумать, что не так с моделью? Особенно, если вы считаете, что семантика поиска сообщений на самом деле является оператором case:

selector = selector1 ifTrue: [ invoke method1 ] 
  ifFalse: [ selector= selector2 ifTrue: [ invoke method2 ] 
   ifFalse: [...] ]]].

Таким образом, вы должны попытаться превратить это в свое преимущество - используйте оператор switch VM вместо написания собственного.

Применяя простой принцип: не спрашивайте (object isSomething ifTrue: [self doSomething]), но говорите (object doSomething), вы можете избежать появления множества ветвей в коде. Конечно, иногда это не применимо и сильно зависит от ситуации, но я часто предпочитаю иметь дополнительную рассылку сообщений, а не другую ветку в коде.

1 голос
/ 14 ноября 2011

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

Вы хотите получить код, который выглядит следующим образом:

Самостоятельное условиеДействие выполняетсяДействие.

или

self conditinAction executeAction: actionArgs

Метод #conditionAction должен будет возвращать уникальный экземпляр объекта для каждого уникального условия (без использования самих операторов case :).

Вы не хотели бы форсировать проблему, создавая классы просто для того, чтобы избежать «операторов case», но в реальном мире у вас уже могут быть уникальные классы, которые вы можете использовать.

...