ファクトリ関数とは
サブクラス(子クラス)のオブジェクトを生成し、それを指し示すスーパークラス(親クラス)のポインタを返す関数のこと。
つまり、スーパークラスを強制的に返して、スーパークラスをベースにサブクラスに応じた振る舞いを行うこと(ポリモーフィズム)を意識させるための関数と言える。
Wikiのファクトリ関数は、ファクトリ関数に継承を使っているが、本記事では継承を使わないシンプルな形。
例
ロールプレイングゲームで「スライム」を動的に登場させたいときを考える。
スーパークラス「モンスター」を継承させると以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <iostream> //モンスタークラス(スーパークラス) class Monster{ public: virtual void move() = 0; //純粋仮想関数 }; //スライムクラス(サブクラス) class Slime :public Monster { public: void move() override final { //オーバーライド std::cout << "ピョンピョン跳ねている" << std::endl; } }; //これがファクトリ関数 Monster *spawnSlime () { return new Slime; } int main() { Monster *slime = spawnSlime(); //強制的にスーパークラスが返ってくる slime->move(); delete slime; } |
move関数:モンスターの移動を表す
サブクラスに応じて振る舞いが異なっている。
26行目:ファクトリ関数
サブクラスであるスライムを動的に生成する関数。返すのはスーパークラスポインタ。
何がいいのか
サブクラスを動的に生成たいときに力を発揮する。
ファクトリ関数がない場合
ポリモーフィズムを意識して、
1 | Monster *slime = new Slime(); |
とスーパークラスで受け取るべきところを
1 | Slime *slime = new Slime(); |
のように左辺がサブクラスで受け取ってしまう可能性がある。
この場合、スーパークラスにはないサブクラス特有の変数や関数を使えてしまい、バグをもたらす可能性がでてしまう。
ファクトリ関数がある場合
動的に生成するとき、このファクトリ関数を使うような指示があれば、強制的にスーパークラスで返ってくるので、自然とポリモーフィズムを意識したソースコードにせざるを得なくなる。