"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