Java.use(better);

前の記事次の記事
Java.use(better);


Episode#06

NullObject パターンの効能 -- if と別れる50の方法


《関連記事》

《目的》
OOP の障害となる「null」の隘路を確認した後で、NullObject パターンを適用して「ポリモフィズム」を促進する術を紹介します。

《動機》
実行時に発生する例外 java.lang.NullPointerException は厄介です。経験を積むほどに発生する頻度は減りますが、それでも皆無にはなりません。

Java/Scala では、null は半人前のオブジェクトとして扱われるので、その対処に苦慮します。Jython/Smalltalk では、null も一人前のオブジェクト(first-class object)として扱えるので、OOP の枠組みで統一できます。

NullPointerException の隘路

二分木〔= binary tree〕を扱う典型的な事例で話を進めます。たとえば、

    Node tree = new Node(4,
      new Node(1, new Node(2), new Node(3)),
      new Node(5));
    System.out.println(tree.size());
    System.out.println(tree.sum());

これを実行すると、次の結果が得られます。

5
15

この結果から、ノードの総数が 5 に、値の合計が 15 になるのが分ります。

これは、次のように実現します。

class Node {
  private int value;
  private Node left;
  private Node right;
  Node(int value) {
    this(value, null, null);
  }
  Node(int value, Node left, Node right) {
    this.value = value;
    this.left  = left;
    this.right = right;
  }
  int size() {
    return 1
      + ((left == null) ? 0 : left.size())
      + ((right == null) ? 0 : right.size());
  }
  int sum() {
    return value
      + ((left == null) ? 0 : left.sum())
      + ((right == null) ? 0 : right.sum());
  }
}

null を扱うときには、NullPointerException が発生しないように配慮します。それには、if 文や条件演算子 ?: に伴う条件式などが必要です。そのため、コードが複雑で見通しも悪くなるだけでなく、バグの温床になりがちです。

■ NullObject パターンの適用

この問題を解決するために「NullObject パターン」を導入します。すると、

  int size() {
    return 1 + left.size() + right.size();
  }
  int sum() {
    return value + left.sum() + right.sum();
  }

if 文や条件演算子 ?: に伴う条件式が不要になるので、コードが簡潔で見通しも良くなります。

 ̄これは、次のように実現します。

class Node {
  static final NullNode nullNode = new NullNode();
  Node() {}

  Node(int value) {
    this(value, nullNode, nullNode);
  }
}
class NullNode extends Node {
  int size() { return 0; }
  int sum() { return 0; }
}

新たなクラス NullNode を用意するとともに、null に代えて、そのインスタンス nullNode を指定します。ここでは、引数を持たないデフォルトコンストラクターが必要になります。


 ↑ TOP

》作業中です《

update*13/02/06 20:23:52

♪ 八橋(やつはし)



出典 ☞ http://shimayu.co.jp/modules/myalbum/photo.php?lid=98