Java.use(better);

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


Episode#07

NullObject パターンの事例 -- if と別れる50の方法


《関連記事》

■ タイルを配置する: NullObject パターンの応用

これで準備が整いました。空白部分を16番目のタイル nullObject と見なせるので、すべてをオブジェクト指向の枠組みで扱えます。

    items = new Vector();
    ...
    for (int y = 0; y < dim; y++) {
      for (int x = 0; x < dim; x++) {
        int value = x + y*dim + 1;
        if (value == dim2) break;
        items.add(new Tile(x, y, value));
      }
    }
    items.add(Tile.nullObject);

15枚のタイル Tile を配置した後で、空白部分に16番目のタイル nullObject を配置します。

■ タイルをスライドさせる: NullObject パターンの応用

タイルをスライドできるのは、空白部分 nullObject と接する場合だけです。

class Tile ...
  public boolean move() { return move(nullObject); }

メソッド move() では、タイルをスライドさせるとき、引数に空白部分 nullObject を指定します。そして、実際にタイルをスライドさせるとき、

  private boolean move(Tile n) {
    boolean b = isInContactWith(n);
    if (b) swap(n);
    return b;
  }

メソッド move(Tile) では、クリック選択したタイルが、空白部分 nullObject と接する isInContactWith ときだけ、お互いの座標を交換 swap します。すると、再描画するときに、タイルが移動したように見えます。
メソッド move() は公開していますが、メソッド move(Tile) は非公開です。そのため、引数に指定した nullObject に依存するという情報は、他のオブジェクトから隠蔽されます(情報隠蔽の原則)。

■ ハリウッドの原則: イベント処理

抽象クラス MouseAdapter を利用すると、インターフェース MouseListener/MouseWheelListener/MouseMotionListener に準拠するメソッド群を実現するのが容易になります。たとえば、

    addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent e) { update(e); }
    });

クリック選択したイベントを処理するときに、メソッド mouseClicked だけを実現すればいいので、手間が掛かりません。ここでは、抽象クラス MouseAdapter に準拠する、名前を持たない具象クラスを実現したことになります。具体的な処理は、下請けメソッド update に任せます。今回は、選択したタイルだけを移動させますが、並んだタイルをまとめて移動させたいときは、update を改良します。

  private void update(MouseEvent e) {
    Shape s = detect(e);
    if (s.move()) repaint();
  }

クリック選択したタイルを特定 detect して、それを移動 move したときだけ再描画 repaint します。ここで注目に値するのは、メソッド paintComponent を呼び出さないことです。「ハリウッドの原則」に従うなら、提供者(プログラマー)としての自分が定義したメソッドを、利用者(プログラマー)として自分で呼び出してはいけません。それを呼び出すための仕掛を用意する責務は、自分ではない提供者(プログラマー)に委ねます。
《義務》利用者(プログラマー)は、メソッド paintComponent を用意するだけで、これを呼び出すコードを書きません。《責任》これを呼び出すのは利用者(プログラマー)です。ハリウッドの原則に従うと、プログラマーが責務(責任/義務)を負い、利用者/提供者の役割分担を明確になるので、共同作業によるプログラミングの能率が上がります。

  public void paintComponent(Graphics g) {
    paintItems(g);
  }

再描画を行うメソッド paintComponent では、具体的な処理を下請けメソッド paintItems に委ねます。

 ↑ TOP

》作業中です《

update*13/02/24 23:16:13