Java.use(better);
■ タイルを配置する: 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
》作業中です《