礼儀実装

2004年8月12日

クラスを記述する場合、多くはクラスの機能がそのクラスにとって意味を成すように努めます。しかし、クラスが本来従うべき、より高度なインターフェイスに適合できるように、機能を追加することが理にかなっている場合があります。

この最も一般的でわかりやすい例は、複合パターンを使用する場合に発生します。単純なコンテナの例を考えてみましょう。他のボックスと象を入れることができるボックスがあります(これは仮想的な象の利点です)。ボックスの中にあり、ボックスの中にあるボックスの中にある象の数を考慮して、ボックスの中にいる象の数を把握したいと考えています。もちろん、その解決策は、単純な再帰です。

# Ruby
class Node
end

class Box < Node
  def initialize 
    @children = []
  end
  def << aNode
    @children << aNode
  end
  def num_elephants
    result = 0
    @children.each do |c|
      if c.kind_of? Elephant
        result += 1
      else
        result += c.num_elephants
      end
    end
    return result
  end
end

class Elephant < Node
end

今、num_elephantskind_of?テストは、オブジェクトの種類をテストする条件を警戒する必要があるため、不自然です。一方、代替手段はありますか。結局のところ、象はボックスや象を含むことができないため、テストを行っています。したがって、内部に何頭の象がいるかを質問するのは理にかなっていません。象に、中に何頭の象がいるか尋ねることは、象は象を含めることができないため、私たちの世界のモデルには合わないのです。それが現実世界をモデル化していないと言うかもしれませんが、私の例は、その議論には少し奇抜すぎるように感じます。

しかし、コンポジットパターンを使用する人は、条件を回避するためによくメソッドを提供します。つまり、次のようになります。

class Node
  #if this is a strongly typed language I define an abstract
  #num_elephants here
end

class Box < Node
  def initialize 
    @children = []
  end
  def << aNode
      @children << aNode
  end
  def num_elephants
    result = 0
    @children.each do |c|
      result += c.num_elephants
    end
    return result
  end
end

class Elephant < Node
  def num_elephants
    return 1
  end
end

多くの人がこの種のことに非常に困惑していますが、コンポジット構造をスイープするコードの論理を大幅に簡素化します。私はそれを、葉クラス(象)が階層内のノードとしての役割に対する礼儀として、単純な実装を提供するように考えています。

数学で、数を0乗にすることの定義は、どのような数も0乗にすると1になるというものです。しかし、直感的には、どの数もそれ自体に0回乗算すると1になるというのは意味が通らないと思います。なぜゼロではないのでしょうか。しかし、定義のおかげで、すべての数学がうまく機能します。そのため、私たちは疑いを保留して定義に従います。

モデルを作成するたびに、世界をどのように認識したいかに合わせてモデルを設計しています。モデルを簡略化することができれば、礼儀実装は有益です。

2014年8月27日に再投稿されました。