问题
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