相互参照している 2 つのクラスがある。これらの関連を疎にしたい。そのような場合には、互いの関係に注目した関連クラスを中間に作成することによって、結合を弱くすることができる。UML で言うところの「社員」と「会社」が「雇用」の関係で表された図がそれなのだが、UML ではピンと来なかったので、身近なコードに置き換えてみる。
勇者 1000 人とモンスター 1000 匹が戦う「Heroes vs. Monsters」というストラテジーゲームがあるとする。このゲームの肝である戦闘を管理したい。しかし、勇者とモンスター間の攻撃は多対多となるために、クライアントは全ての勇者、又はモンスターのリストを総ざらいして、各戦闘を実行しなければならない。
そこで、勇者とモンスターの「敵対関係」に着目した Battle クラスを作成する。Battle という関連クラスが仲介することで、各キャラクタは自分の敵を管理する必要が無くなる。
勇者
class Hero {
/**
* 攻撃をする
* @param target 攻撃対象
*/
public function attack(target:Monster):Void;
}
モンスター
class Monster {
/**
* 攻撃をする
* @param target 攻撃対象
*/
public function attack(target:Hero):Void;
}
戦闘
class Battle {
private var hero:Hero;
private var monster:Monster;
public function getHero():Hero;
public function getMonster():Monster;
}
Battle クラスに攻撃の実装をしても良いが、コレクションクラス BattleList を作成し、クライアントは、このコレクションに対して操作を行う。
戦闘リスト
class BattleList {
private var battles:Array;
/**
* 戦闘を開始する
*/
public function openFire():Void {
for (var i:Number = 0; i < this.battles.length; i++) {
var battle:Battle = this.battles[i];
var hero:Hero = battle.getHero();
var monster:Monster = battle.getMonster();
//互いに攻撃する
hero.attack(monster);
monster.attack(hero);
}
}
}
openFire() メソッドを呼ぶことで、発生している全ての戦闘が開始される。