ゲームが作れるようになるまでがんばる日記

ゲーム制作のことを中心にゲームに関することを書いています

Visitor

データ構造を持つクラスとそれに処理を行うクラスを分離する。
データのクラスに行いたい処理のメソッドを追加するのではなく、処理を行うクラスを作成し、それを受け入れるようにする。こうすることにより処理内容が変わってもデータのクラスを修正する必要が無くなる。
さて、ゲームで考えてみよう。
武器や防具のアイテムを表すクラスとそれに対して何か処理を行うクラスに分けてみる。
Visitor.java 処理を行う抽象クラス

public abstract class Visitor {
    public abstract void visit(Weapon weapon);
    public abstract void visit(Armor armor);
}

Acceptor.java 処理を行う抽象クラスVisitorを受け取るインタフェース

public interface Acceptor {
    public abstract void accept(Visitor v);
}

Stuff.java アイテムを表す抽象クラス Acceptorを実装する

public abstract class Stuff implements Acceptor {
    public abstract String getName();
}

Weapon.java 武器を表すクラス

public class Weapon extends Stuff {
    private String name;
    public Weapon(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void accept(Visitor v) {
        v.visit(this);
    }
}

Armor.java 防具を表すクラス

public class Armor extends Stuff {
    private String name;
    public Armor(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void accept(Visitor v) {
        v.visit(this);
    }
}

DispVisitor.java アイテムを表示するクラス

public class DispVisitor extends Visitor {
    public void visit(Weapon weapon) {
        System.out.println("W " + weapon.getName());
    }
    public void visit(Armor armor) {
        System.out.println("A " + armor.getName());
    }
}

Main.java メイン

import java.util.Iterator;
import java.util.Vector;

public class Main {
    public static void main(String[] args) {
        Vector stufflist = new Vector();

        stufflist.add( new Weapon("Sword") );
        stufflist.add( new Weapon("Knife") );
        stufflist.add( new Armor("Cloth") );
        stufflist.add( new Armor("Plate") );

        DispVisitor disp = new DispVisitor();
        Iterator it = stufflist.iterator();
        while( it.hasNext() ) {
            Stuff stuff = (Stuff)it.next();
            stuff.accept(disp);
        }
    }
}

実行結果

W Sword
W Knife
A Cloth
A Plate

DispVisitorクラスは武器だったらWを、防具だったらAを付けて表示するようになっている。
他にもアイテムに対して行いたい処理がある場合は、Visitorクラスを継承して作成すれば良いので簡単に追加できる。ところがアイテムの種類が増えるような場合は今までのVisitorのクラスにも追加しなくてはならないため大変。
このVistorパターンのようにacceptとvisitが組になって処理が決定されるようなことをダブルディスパッチと呼ぶ。C++のテクニックが書かれた本「More Effective C++」に例が載っているらしい。今度買って読んでみよう。


参考文献:Java言語で学ぶデザインパターン入門
参考:ギコ猫とVisitorパターン