Lukas,
To clarify for you, the extra database accesses are because when the
database accesses a PRDecorated node it loads the decorations in. Then
seeing that PRChildren is present it generates a second access to get
the contents of PRChildren only to find that it is empty. This is extra
work (and time) for no net purpose.
At the moment the problem is that many operations that involve children
are doing so via PRStructure-#childrenDecoration whose default behaviour
is to add an empty PRChildren instance to its decorations even if it is
not actually needed.
To be honest I love the clean design, even with empty PRChildren
instances. It's just a shame when pragmatic considerations mess with our
nice designs. Since I indicated that there are other ways of solving
this problem I will list a few below.
I constructed the children-accessing interface in order to satisfy the
needs of the users of #childrenDecoration which are primarily the
commands and the tests. Specifically:
PRCommand-#validateName: aString of: aChildStructure in: aStructure
PRCommand-#uniqueName: aString in: aStructure
PRChangeEnvironmentCommand-#doExecute
PRAddCommand-#doExecute
PRCopyCommand-#doExecute
PRMoveCommand-#doExecute
PRStructure-#remove
Solution Options:
1. child-accessing interface as discussed.
2. Magma before serializing any PRDecorated looks to see if there are
any empty PRChildren and removes them before writing to its buffers. [ I
think that this will work , though I am not 100% certain, but then we
have PRChildren being created and destroyed over and over.]
3. Use an interface such as
aStructure withChildren: [ :children | children add: ( aNewPage ) ]
where #withChildren: cleans up afterwards.
4. Rewrite the commands above to use some form of visitor as you suggest
below:
I wonder where from these children are accessed? No part of the code
should directly access the children of a structure, but instead walk
over them using a visitor. Of course, I might have missed something ...
Note that subclasses of PRStructure might override
#childrenDecorationClass to use a completely different decoration for
children.
fair enough.
and an access
interface defined for children...
#addChild:
#childAt:
#childAt:ifAbsent:
#childAt:ifPresent:
#childrenIncludes:
#removeChild:
I don't see why this would help. As far as I see none of my code uses
any of this functionality directly.
I think that you forgot the command actions #doExecute etc. see above
It is not the way Pier is designed. Compared to
SmallWiki I wanted to
factor out all the behavior related to children to a different
(pluggable) object
Fair enough, I thought as much, but when I found
PRStructure-#addChild:
it indicated to me that you had thought of having a child-accessing
interface of sorts, and so I simply completed the set to provide the
functionality actually used in the image.
I had a look at the third option and this is what I came up with
PRDecorated>>newDecorationOfClass: aClass in: aBlock
| decoration result |
decoration := aClass new.
result := aBlock value: decoration.
decoration isEmpty ifFalse: [ self addDecoration: decoration ].
^result
PRDecorated>>decorationOfClass: aClass in: aBlock
| decoration result |
decoration := self decorationOfClass: aClass
ifAbsent: [ ^self newDecorationOfClass: aClass in: aBlock ].
result := aBlock value: decoration.
decoration isEmpty ifTrue: [ self removeDecoration: decoration ].
^result
PRStructure>>childrenIn: aBlock
^ self decorationOfClass: self childrenDecorationClass in: aBlock
and so this enables things like
PRCommand>>uniqueName: aString in: aStructure
"Answer an unique structure name with the prefix aString within the
parent aStructure."
| index name |
(aStructure notNil
and: [ aStructure childrenIn: [ :children | children includes:
aString ] ])
ifFalse: [ ^ aString ].
index := 1.
[ aStructure childrenIn: [ :children | children includes: (name :=
aString , ' ' , (index := index + 1) asString) ] ]
whileTrue.
^ name
would that be better?
Keith