【C++】ファクトリメソッドを実装したよ

 

今日はデザインパターンの一つである、ファクトリメソッドについてまとめます。

スポンサードサーチ

ファクトリメソッドとは?

簡単に一行でまとめると、

インターフェースを介することで、オブジェクト生成を柔軟に行えるようにする。

といったものです。

A君

は??

3lonco

おっしゃっていること分かります・・・ゆっくり見ていきましょう。

スポンサードサーチ

従来のオブジェクト生成方法

一般的にはオブジェクトを生成するときは、下記の様に行うと思います。

class *a_1= new ClassA();
class *a_2 = new ClassA(); 

問題なく、オブジェクトは生成できますが、これの問題点は、

具象クラスの名前を明示的に書くので、同じクラスのオブジェクトを複数生成したいときには、そのクラスの名前がコードの複数個所に出てくることにあります。それゆえに、コードの拡張や保守の観点からめんどくさくなります。

具象クラスを明示してオブジェクトを生成するので、

・新しくクラスを追加するとき

・使用するクラスを切り替えたいとき

に具象クラスが出てくる個所をすべて修正する必要がある。

 

以上を踏まえて、ファクトリメソッドでは、

インターフェースを通して、オブジェクトの生成を行うことで、生成される側と生成する側の結びつきを弱くすることで、クラスの切り替えや新規クラスの追加を柔軟に行っていきます。

3lonco

何言っているかわからないと思います。具体例を見ながら進めてきましょう。

スポンサードサーチ

適用場面

現状-ダミークラスを使って開発を進めて、後で実際のクラスに切り替えたい

といった状況があったとします。後で、実際に開発されたクラスを使っていくとします。

具体例として、Webカメラから画像を取得するクラスについて考えます。
現在はWebカメラから画像を取れないので、一旦はローカルにある画像を読み込んで、処理していくことにします。

・後々はwebカメラの画像を撮像して、その画像を取得していく。

・現在はwebカメラの画像が取れないので、一旦は画像を読み込んで進めていく。

3lonco

行ってみよう!

ファクトリメソッドを使う前


using namespace std;

class ReadImageObject {
public:
	ReadImageObject() {cout<< "画像を読み込みました。"; }


};
int main() {
	ReadImageObject *temp = new ReadImageObject("path");
}

ファクトリメソッドを使う前は上記の様なコードになります。これの何に問題があるかわかりますか?

これの問題点は、後々にGetWebCameraObjectが作られた時に、

ReadImageObject *temp = new ReadImageObject();

GetWebCameraObject *temp = new GetWebCameraObject ();

と変更しないといけません。これが一行二行であれば問題ございません。もし、これが大きなアプリケーションの場合、相当な個所を修正しなければなりません。

これを解決するのが、ファクトリメソッドです。

スポンサードサーチ

ファクトリメソッドを適用する。


using namespace std;

class DataObject {
public:
	static DataObject* create();
};

class ReadImageObject :public DataObject {
public:
	ReadImageObject() {cout<< "画像を読み込みました。"; }


};

DataObject* DataObject::create(){
	return new ReadImageObject();
}

int main() {
	DataObject* temp = DataObject::create();
}

 

上のコードがファクトリメソッドです。前後の比較では、

■適用前

・newを使用して、オブジェクトを取得。

・画像読み込みするクラス(ReadImageObject)の名前をクライアント側で明示的に指定。

■適用後

・メソッドの呼び出し側でオブジェクトを取得する。

・クライアント側では、Webカメラ(GetWebCameraObject)か画像読み込み(ReadImageObject)なのか気にする必要がない

では、実際にWebカメラ読み込みクラスが開発されました。その時のクライアント側の動作はこうなります。

適用前


using namespace std;

class ReadImageObject {
public:
	ReadImageObject() {cout<< "画像を読み込みました。"; }


};

class GetWebCameraObject {
public:
	GetWebCameraObject() { cout << "Webカメラから画像を読み込みました。"; }


};

int main() {
	//ReadImageObject* temp = new ReadImageObject("path");
	GetWebCameraObject* temp = new GetWebCameraObject();
}

適用後


using namespace std;

class DataObject {
public:
	static DataObject* create();
};

class ReadImageObject :public DataObject {
public:
	ReadImageObject() { cout << "画像を読み込みました。"; }


};

class GetWebCameraObject :public DataObject {
public:
	GetWebCameraObject() { cout << "Webカメラを読み込みました"; }
};


DataObject* DataObject::create() {
	//return new ReadImageObject();修正箇所
	return new GetWebCameraObject();
}

int main() {
	DataObject* temp = DataObject::create();
}

どうでしょうか?見ていただくとわかるように、クライアント側は一切の変更を加えていません。
クラスの提供者側が変更を加えただけですので、クライアント側の修正はこの場合はありません。また、あったとしても適用前に比べてはるかに少なくなります。

まとめ

以下まとめです。

■適用前

・newを使用して、オブジェクトを取得。

・画像読み込みするクラス(ReadImageObject)の名前をクライアント側で明示的に指定。

■適用後

・メソッドの呼び出し側でオブジェクトを取得する。

・クライアント側では、Webカメラ(GetWebCameraObject)か画像読み込み(ReadImageObject)なのか気にする必要がない

大変便利なファクトリメソッドについて紹介しました。ぜひ、この記事が参考になれば幸いです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です