0-1-Many Pattern
Maloney
johnm at wdi.disney.com
Tue Sep 8 18:56:45 UTC 1998
I much prefer your third approach. It keeps the entire implementation
inside Element, where it belongs. I don't consider the nil check
or the isCollection check to be bad style; they reflect very clearly
the implementation choices for 0, 1, and many elements. Adding a comment
to subelementsDo: would make the entire pattern completely
understandable just by reading this one method.
-- John
>It is often the case that you want to create an Element object which
>contains zero or more subelements. The most straight forward way is to use
>an instance var 'subelements' that aways contains a Collection of some
>kind. However, sometimes for space reasons it is compelling to use the
>following:
>
>Subelement Count Value stored in var 'subelements'
>0 nil
>1 direct Element reference
>2+ Collection of Elements
>
>To have a method such as Element>>#subelementsDo: work in a polymorphic
>fashion you might define:
>
>Object>>#do: aBlock
> ^aBlock value: self
>
>UndefinedObject>>#do:: aBlock
> ^self
>
>As mentioned in previous posts, to avoid diluting the protocol of #do: and
>hiding errors, a separate message should be sent. The question is what
>would be best? This especially a problem when you want to make use of the
>existing Collection enumeration protocol beyond simple #do:.
>
>Two solution come immediately to mind:
>
>1)
>Object>>#asCollection
> ^{self}
>
>UndefinedObject>>#asCollection
> ^#()
>
>Collection>>#asCollection
> ^self
>
>Element>>#subelements
> ^subelements asCollection
>
>Element>>#subelementsDo: aBlock
> ^self subelements do: aBlock
>
>Element>>#detectSubelement: aBlock
> ^self subelements detect: aBlock
>
>
>2)
>Object>>#apply: aBlock
> ^aBlock value: subelements
>
>UndefinedObject>>#apply: aBlock
> "no op"
>
>Collection>>#apply: aBlock
> ^self do: aBlock
>
>Element>>#subelementsDo: aBlock
> ^subelements apply: aBlock
>
>Element>>#detectSubelement: aBlock
> subelements apply: [:each | (aBlock value: each) ifTrue: [^each]].
> ^nil
>
>Though Solution 1 avoids requiring an Element to hold a Collection if it
>doesn't have to, it perpetually creates and disposes Arrays. It does
>however have the advantage of implicitly working with the entire
>enumeration protocol (e.g. detecting).
>
>Solution 2 is both statically and dynamically space efficient but requires
>rebuilding of any enumeration protocol beyond #do:.
>
>Taking a third approach, the non polymorphic method would be:
>
>3)
>Element>>#subelementsDo: aBlock
> subelements ifNil: [^nil].
> ^subelements isCollection
> ifTrue: [subelements do: aBlock]
> ifFalse: [aBlock value: subelements]
>
>Element>>#detectSubelement: aBlock
> self subelementsDo:
> [:subelement | (aBlock value: subelement) ifTrue: [^subelement]].
> ^nil
>
>
>Which technique is recommended?
>
>--Maurice
>
>---------------------------------------------------------------------------
> Maurice Rabb 773.281.6003 Stono Technologies, LLC Chicago, USA
More information about the Squeak-dev
mailing list
|