トップページ > デザインパターン > Factory Methodパターン



目的

オブジェクトを生成するときのインターフェースだけを規定して、実際にどのクラスをインスタンス化するかはサブクラスが決めるようにする。Factory Methodパターンは、インスタンス化をサブクラスに任せる。


Factory Method

public function create()
{
	var sprite:Sprite = new Sprite();	// before
	var sprite:Sprite = getSprite();	// after
}
 
public function getSprite():Sprite
{
	// サブクラスでSpriteを継承している子クラスオブジェクトを返す
}
 
new Sprite()のように直接インスタンスを作るのではなく、新しくメソッドを作り、そのメソッドからインスタンスを取得するように変更します。
メソッドをサブクラス側でオーバーライドし、生成するインスタンスをサブクラス側で決めるようにしたのがFactory Methodパターンになります。

外側のクラスにオブジェクトを提供する場合
例えば、利用するデータベースの種類が複数あり、それをクラスで選択させる場合です。

Database.as
package  
{
	public class Database 
	{
		public function connect(address:String, id:String, password:String, databaseName:String):DBConnection
		{
			throw new Error("オーバーライドしてメソッドの中身を書き換えてください");
		}
	}
}
 
データベースのクラスをまとめる親クラスであるDatabase.asです。
DBに接続する際はconnect()を使用しますが、何のDBに繋ぐかはサブクラスに任せます。


MySQL.as
package  
{
	public class MySQL extends Database
	{
		override public function connect(address:String, id:String, password:String, databaseName:String):DBConnection
		{
			return new MySQLConnection(address, id, password, databaseName);
		}
	}
}
 
Oracle.as
package  
{
	public class Oracle extends Database
	{
		override public function connect(address:String, id:String, password:String, databaseName:String):DBConnection
		{
			return new OracleConnection(address, id, password, databaseName);
		}
	}
}
 
MySQLクラスはMySQLの、OracleクラスはOracleのコネクションを返します。


package
{
	import flash.display.Sprite;
 
	public class Main extends Sprite
	{
		public function Main()
		{
			var address:String = "localhost";
			var id:String = "root";
			var pass:String = "password";
			var databaseName:String = "db_flash";
 
			var db:Database = new MySQL();
			trace(db.connect(address, id, pass, databaseName)); // [object MySQLConnection]
 
			db = new Oracle();
			trace(db.connect(address, id, pass, databaseName)); // [object OracleConnection]
		}
	}
}
 

自クラスのメソッドにオブジェクトを提供する場合
オブジェクトの生成先が同じメソッド内である場合です。

Shape.as
public function create()
{
	var sprite:Sprite = getSprite();
}
 
protected function getSprite():Sprite
{
	throw new Error("オーバーライドしてメソッドの中身を書き換えてください");
}
 
Triangle.as
override protected function getSprite():Sprite
{
	return DrawShape.create(DrawShape.TRIANGLE);
}
 
Rectangle.as
override protected function getSprite():Sprite
{
	return DrawShape.create(DrawShape.RECTANGLE);
}
 


親クラスの処理

親クラスで例外を投げる場合
package  
{
	public class BaseClass
	{
		public function factoryMethod():*
		{
			throw new Error();
		}
	}
}
 
メソッドの実装を完全にサブクラスに委ねるなら、親クラスをnewする必要はないので、メソッド内で例外を投げるようにします。

親クラスにデフォルトの実装をしておく場合
package  
{
	public class Database
	{
		public function connect(address:String, id:String, password:String, databaseName:String):DBConnection
		{
			return new MySQLConnection(address, id, password, databaseName);
		}
	}
}
 
例えば、通常はMySQLに接続するが、それ以外のDBに接続したい場合は、オーバーライドしてメソッドの中身を書き換えてくださいという場合です。

パラメータ値によって返すオブジェクトを変える場合
package  
{
	public class Database 
	{
		public static const MYSQL:String = "mysql";
		public static const ORACLE:String = "oracle";
		public var selectDBName:String;
 
		public function connect(address:String, id:String, password:String, databaseName:String):DBConnection
		{
			switch (selectDBName)
			{
				case MYSQL:
					return new MySQLConnection(address, id, password, databaseName);
					break;
				case ORACLE:
					return new OracleConnection(address, id, password, databaseName);
					break;
				default:
					return null; // throw new Error("先にDB名を選択して下さい");
					break;
			}
		}
	}
}
 
package  
{
	public class Oracle extends Database
	{
		public function Oracle()
		{
			selectDBName = ORACLE;
		}
	}
}
 
package  
{
	public class MySQL extends Database
	{
		public function MySQL()
		{
			selectDBName = MYSQL;
		}
	}
}
 
親クラス側で、ifやswitchを使用し、パラメータ値によって返すオブジェクトを変えるパターンです。
このパターンの場合、サブクラス側はメソッドをオーバーライドするのではなく、パラメータ値を書き換えるだけでOKです。

|新しいページ|検索|ページ一覧|RSS|@ウィキご利用ガイド | 管理者にお問合せ
|ログイン|