Abstract Factoryパターンは、オブジェクト(群)の一括生成や一括入れ替え(模様替え)といったマクロ的な作業を行う際に便利な手法である。 具体的な処理はFactoryと呼ばれるクラスが一括して管理し、クライアントにはFactoryクラスのインターフェイスのみが提供される。 クライアントはFactoryクラス内部の具体的なプロセスを知る必要がなく、 Factoryクラスのインターフェイスを実装しているクラスであれば何でもFactoryクラスとして利用することができる。 これがAbstract Factoryと呼ばれる所以である。
個人的な見解だが、Abstract Factoryというネーミングはパターン全貌を説明しているとは思えないためあまり好きではない。 実際、"Gamma et al. - Design Patterns"ではKitパターンとしても紹介されており、こちらの方が好みである。
以下の例は、RPG(例えばモンスターハンター)におけるハンター(Hunter)の武器と防具の一括着せ替えをAbstract Factoryパターンを用いて行っている。 ハンターの装備に関するルールは以下のとおりである。
このような条件の場合、近接・遠距離間の武器の変更と防具の変更は同時に行われなければならず、 一般的なRPGよりも装備の変更が面倒くさくなるものと予想される。そこで装備の着せ替え機構にAbstract Factoryパターンを用い、その面倒くささの緩和を試みる。 具体的には以下のようになるだろう。
/** * Abstract factory main.as * * @date 2009/08/25 * @author boreal-kiss.com */ package { import flash.display.Sprite; public class main extends Sprite{ public function main(){ var hunter:Hunter = new Hunter(); var factory:Factory = new AttackerFactory(hunter); factory.setAll(); trace(hunter); factory = new GunnerFactory(hunter); factory.setAll(); trace(hunter); } } }
//main.as output The hunter wears: [class AttackerWeapon]: weapon for attackers [class AttackerArmor]: armor for attackers The hunter wears: [class GunnerWeapon]: weapon for gunners [class GunnerArmor]: armor for gunners
//Hunter.as package{ public class Hunter{ protected var _weapon:Weapon; public function set weapon(value:Weapon):void{ _weapon = value; } public function get weapon():Weapon{ return _weapon; } protected var _armor:Armor; public function set armor(value:Armor):void{ _armor = value; } public function get armor():Armor{ return _armor; } /** * Constructor */ public function Hunter(weapon:Weapon=null, armor:Armor=null){ _weapon = weapon; _armor = armor; } public function toString():String{ return "The hunter wears: \n" + _weapon.toString() + "\n" + _armor.toString() + "\n"; } } }
//Factory.as package{ //Abstract class. public class Factory{ protected var _hunter:Hunter; /** * Constructor */ public function Factory(hunter:Hunter){ _hunter = hunter; } public function setAll():void{ this.setWeapon(); this.setArmor(); } protected function setWeapon():void{ //Must be overridden in a subclass. } protected function setArmor():void{ //Must be overridden in a subclass. } } }
//AttackerFactory.as package{ public class AttackerFactory extends Factory{ /** * Constructor */ public function AttackerFactory(hunter:Hunter){ super(hunter); } override protected function setWeapon():void{ _hunter.weapon = new AttackerWeapon(); } override protected function setArmor():void{ _hunter.armor = new AttackerArmor(); } } }
//GunnerFactory.as package{ public class GunnerFactory extends Factory{ /** * Constructor */ public function GunnerFactory(hunter:Hunter){ super(hunter); } override protected function setWeapon():void{ _hunter.weapon = new GunnerWeapon(); } override protected function setArmor():void{ _hunter.armor = new GunnerArmor(); } } }
//Weapon.as package{ //Abstract class. public class Weapon{ /** * Constructor */ public function Weapon(){ } public function toString():String{ return Object(this).constructor; } } }
//AttackerWeapon.as package{ public class AttackerWeapon extends Weapon{ /** * Constructor */ public function AttackerWeapon(){ super(); } override public function toString():String{ return super.toString() + ": weapon for attackers"; } } }
//GunnerWeapon.as package{ public class GunnerWeapon extends Weapon{ /** * Constructor */ public function GunnerWeapon(){ super(); } override public function toString():String{ return super.toString() + ": weapon for gunners"; } } }
//Armor.as package{ //Abstract class. public class Armor{ /** * Constructor */ public function Armor(){ } public function toString():String{ return Object(this).constructor; } } }
//AttackerArmor.as package{ public class AttackerArmor extends Armor{ /** * Constructor */ public function AttackerArmor(){ super(); } override public function toString():String{ return super.toString() + ": armor for attackers"; } } }
//GunnerArmor.as package{ public class GunnerArmor extends Armor{ /** * Constructor */ public function GunnerArmor(){ super(); } override public function toString():String{ return super.toString() + ": armor for gunners"; } } }