Refactoring if-chains in Smalltalk without class explosion

时光毁灭记忆、已成空白 提交于 2019-12-23 09:32:30

问题


As Smalltalk discourages the use of caseOf:, what aternatives exists to implement the following situation without class explosion?

self condition1
        ifTrue: [ self actionForCondition1 ]
        ifFalse: [ 
            self condition2
                ifTrue: [ self actionForCondition2 ]
                ifFalse: [ 
                    self condition3
                        ifTrue: [ self actionForCondition3 ]
                        ifFalse: [ ....  ] ] ]

回答1:


If you scroll to near the end of

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

you will find the sentence

"There are four ways to express a case-statement in Smalltalk."

followed by links to examples.

The text is in the middle of a slightly longer series of pages and makes occasional references to hypothetical tutor and students ina Smalltalk course for purposes of illustration; you can ignore that for the purposes of your question)




回答2:


Depends on how your conditions exactly look like?

  • If your conditions are type tests

    anObject isKindOf: aClass
    

    you can dispatch on the class instead, that means you call an action method on anObject.

  • If your conditions are equality tests

    anObject = anotherObject
    

    you can use a dictionary with the object as key and the action as a block closure.

  • As a last restort and if nothing else helps you might want to rewrite the proposed code to avoid unnecessary nesting:

    self condition1
        ifTrue: [ ^ self actionForCondition1 ].
    self condition2
        ifTrue: [ ^ self actionForCondition2 ].
    self condition3
        ifTrue: [ ^ self actionForCondition3 ].
    ...
    



回答3:


I think, at the moment when you have to write this code, i would ask myself, why i have to write so many conditions in order to proceed further with a single step in my algorithm. Maybe it is time to think what is wrong with model? Especially, if you consider that a message lookup semantics is actually a case statement:

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

So you should try to turn this into your advantage - use VM's switch statement instead of writing own.

By applying a simple principle: do not ask (object isSomething ifTrue:[ self doSomething ]) but tell (object doSomething), you can avoid having many branches in the code. Of course, sometimes it is not applicable and heavily depending on situation, but i often prefer to have extra message dispatch, rather than another branch in code.




回答4:


You should take a look at double dispatching. Depending upon how the tests and actions are implemented you may be able to use double dispatching to great advantage.

You want to end up with code that looks like the following:

self conditionAction performAction.

or

self conditinAction performAction: actionArgs

The method #conditionAction would have to return a unique instance of an object for each unique condition (without using case statements itself:).

You wouldn't want to force the issue by creating classes just to avoid "case statements", but in real world you may already have some unique classes that you can leverage.



来源:https://stackoverflow.com/questions/8113497/refactoring-if-chains-in-smalltalk-without-class-explosion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!