Robert Klemme
12/12/2004 11:35:00 AM
"Mikael Brockman" <mikael@phubuh.org> schrieb im Newsbeitrag
news:87hdmscik0.fsf@igloo.phubuh.org...
>I am writing a tree editor. The algorithm for displaying a node is
> recursive. On leaf nodes, it's trivial. Branches need to display all
> their kids.
>
> I would like to implement this with three classes: the Leaf, the
> Branch, and the Node. Leaf & Branch are subclasses of Node.
>
> The problem: nodes are mutable. You can add a kid to a node. If that
> node's a Leaf, it needs to become a Branch.
>
> I can think of three solutions.
>
> - Add a wrapper object around every Node, and give it a #replace
> method.
>
> - Use Object#become from evil.rb.
>
> - Represent nodes and leaves as instances of the same class, and use if
> statements.
>
> I'd like #2 the best if evil.pb wasn't likely to win awards for being
> the nastiest hack of all time. (Props to the authors!) I don't like #1
> or #3, but if I had to choose, I'd go with #3.
>
> Making nodes non-mutable would be annoying and unintuitive, I think.
>
> What would you do?
I would not necessarily change the type of the instance. Instead I had just
class Node and would use strategy / state pattern. Using extend with a
Module (like David suggested) is one way to accomplish this, but it becomes
complitcated if the Branch should become a Leaf again. You could instead
keep an instance around that implements all behavior that depends on the
state 'leaf' vs. 'branch'.
Example:
require 'singleton'
class Node
class Leaf
include Singleton
def leaf?() true end
def each(owner) end
end
class Branch
include Singleton
def leaf?() false end
def each(owner,&b) owner.children.each(&b) end
end
attr_reader :children
def initialize
@children = []
@state = Leaf.instance
end
def leaf?() @state.leaf? end
def branch?() ! leaf? end
def each(&b) @state.each(self,&b) end
def add(node)
@children << node
@state = Branch.instance
end
def remove(node)
@children.delete node
@state = Leaf.instance if @children.empty?
end
end
Kind regards
robert