"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