C++ ファクトリ メソッド
ファクトリ メソッドは、ユーザーがメソッド呼び出しを見ずにインターフェイスを使用できるように、構成を隠しながらオブジェクトを作成するために使用される C++ のオブジェクト作成デザイン パターンです。
C++ のファクトリ メソッド
ファクトリは、ユーザーがクリーンなプログラム インターフェイスとやり取りできるようにするプログラムをプログラマが設計できるようにする仮想コンストラクタです。 これは、オブジェクトの作成自体を親クラス内に隠すことを意味します。
プログラムに親クラスとユーザー サブクラスの 2つのクラスがある場合、コンストラクターを使用すると、2つのクラスが相互に大きく依存することになります。 親クラス内で引き起こされた変更は、サブクラスの後続の変更につながります。
ファクトリの機能は、プログラムの開始時にオブジェクトを記述する機能であり、必要なすべての変更がライブラリ クラス内で行われ、他の場所では行われないため、新しいオブジェクトを追加する機能が開かれます。
C++ の単純なコンストラクター クラス
コード:
#include <iostream>
using namespace std;
// LIBRARY/PARENT(Wire_Sizes) CLASS WITH Two_mm and Four_mm sub-classes
class Wire_Sizes {
public:
virtual void Diameter() = 0;
};
class Two_mm : public Wire_Sizes {
public:
void Diameter() { cout << "This wire is 2mm in diameter" << endl; }
};
class Four_mm : public Wire_Sizes {
public:
void Diameter() { cout << "This wire is 4mm in diameter" << endl; }
};
// CLIENT(User) CLASS
// One thing to note here is that object creation takes place inside the User
// class, which can affect the whole program if changes are to be made to the
// parent class - like adding a new category of wire diameter.
// In this client class, adding a new type will mean adding a new category to
// the existing if-else ladder.
class User {
public:
User(int type) {
// Client explicitly creates classes according to type
if (type == 1)
pDiameter = new Two_mm();
else if (type == 2)
pDiameter = new Four_mm();
else
pDiameter = NULL;
}
~User() {
if (pDiameter) {
delete[] pDiameter;
pDiameter = NULL;
}
}
Wire_Sizes *getDiameter() { return pDiameter; }
private:
Wire_Sizes *pDiameter;
};
// MAIN FUNCTION
int main() {
User *pClient = new User(2);
Wire_Sizes *pDiameter = pClient->getDiameter();
pDiameter->Diameter();
return 0;
}
出力:
This wire is 4mm in diameter
Wire_Sizes
は、Two_mm
と Four_mm
という 2つのサブクラスを持つライブラリまたは親クラスであり、メソッド Diameter()
がオーバーロードされ、メソッドが呼び出されると print ステートメントを返します。
User
クラスでは、パラメーター型は main()
関数から渡された値を取得し、戻り値の型に一致するオブジェクト クラスを作成します。 ~User()
(デストラクタ) は、割り当てられたリソースを破棄し、ポインタをクリアします。
main()
関数はオブジェクト *pClient
を作成し、値 2
を渡します。 この値は User
(クライアント) クラスに渡され、タイプ 2
のオブジェクトが作成され、Wire_Sizes
(親) クラスから タイプ 2
の対応するメソッドが呼び出されます。
これにより、プログラムはそのサブクラスに大きく依存し、コード集約的になります。 この問題を解決するためにファクトリが使用されます。
C++ のコンストラクター クラスにファクトリー メソッドを使用する
コード:
#include <iostream>
using namespace std;
// The three derived classes, Size_two_mm, Size_three_mm, and Size_four_mm,
// contains the printDiameter() method, which is overloaded in all the
// subclasses
enum Size { Size_two_mm, Size_three_mm, Size_four_mm };
class Wire_Sizes {
public:
virtual void printDiameter() = 0;
static Wire_Sizes* Create(Size type);
};
class Twomm : public Wire_Sizes {
public:
void printDiameter() { cout << "This wire is 2mm in diameter" << endl; }
};
class Threemm : public Wire_Sizes {
public:
void printDiameter() { cout << "This wire is 3mm in diameter" << endl; }
};
class Fourmm : public Wire_Sizes {
public:
void printDiameter() { cout << "This wire is 4mm in diameter" << endl; }
};
Wire_Sizes* Wire_Sizes::Create(Size type) {
if (type == Size_two_mm)
return new Twomm();
else if (type == Size_three_mm)
return new Threemm();
else if (type == Size_four_mm)
return new Fourmm();
else
return NULL;
}
class user {
public:
user() {
Size type = Size_three_mm;
pDiameter = Wire_Sizes::Create(type);
}
~user() {
if (pDiameter) {
delete[] pDiameter;
pDiameter = NULL;
}
}
Wire_Sizes* getDiameter() { return pDiameter; }
private:
Wire_Sizes* pDiameter;
};
int main() {
user* pClient = new user();
Wire_Sizes* pDiameter = pClient->getDiameter();
pDiameter->printDiameter();
return 0;
}
出力:
This wire is 3mm in diameter
Size
列挙データ内に、最初にプログラムで使用される 3つのオブジェクトを入力します。
if-else
条件は、Wire_Sizes
(ライブラリ) クラスの直後の新しいコンストラクタ Create()
内に記述されます。 クライアント クラスを変更するよりも、新しいオブジェクトを追加する方が簡単です。
コンストラクターはパラメーター type
を使用して値を受け取り、if-else
ラダー内でそれを照合します。 一致が正の場合は対応する関数が呼び出され、一致が負の場合は NULL
が返されます。
user
クラスは明示的にオブジェクトを作成しませんが、ファクトリ メソッド Create()
に型を渡します。 オブジェクト Size_three_mm
が type に渡され、コンストラクタ クラス Create()
が代入演算子を使用して pDiameter
に割り当てられます。
~user()
(デストラクタ) は、クラスの最後に割り当てられたリソースを破棄し、NULL
を変数 pDiameter
に割り当てます。 コンストラクタ getDiameter
内では、変数 pDiameter
が返されます。
main()
メソッドは user
クラスのオブジェクト *pClient
を作成し、このオブジェクトは pDiameter()
メソッドと呼ばれます。 getDiameter()
メソッドは pDiameter
変数を返します。この変数には、型内に格納された値があります。
構文 Wire_Sizes * pDiameter = pClient->getDiameter();
getDiameter()
メソッドの値をNULL
を格納するpDiameter
に渡し、printDiameter()
メソッドを呼び出します。
C++ の具象クラスと抽象ファクトリ メソッド
メソッドまたはクラスが宣言されている場合、それは何かを返すことができないため抽象クラスとして知られ、そのメソッドまたはクラスが定義されている場合、それは具象として知られています。 具象クラスは、ファクトリ内の要件に従ってインスタンス化して呼び出すことができます。
コード:
#include <iostream>
using namespace std;
// BASE CLASS
class Concrete_Example {
public:
virtual ~Concrete_Example() {}
virtual std::string Operation() const = 0;
};
class ExampleProduct1 : public Concrete_Example {
public:
std::string Operation() const override {
return "{Product 1 is instantiated}";
}
};
class ExampleProduct2 : public Concrete_Example {
public:
std::string Operation() const override {
return "{Product 2 is instantiated}";
}
};
// CREATOR CLASS
class Create {
public:
virtual ~Create(){};
virtual Concrete_Example* FactoryMethod() const = 0;
std::string SomeOperation() const {
Concrete_Example* concrete_Example = this->FactoryMethod();
std::string result = "Client Code" + concrete_Example->Operation();
delete concrete_Example;
return result;
}
};
class ExampleCreator1 : public Create {
public:
Concrete_Example* FactoryMethod() const override {
return new ExampleProduct1();
}
};
class ExampleCreator2 : public Create {
public:
Concrete_Example* FactoryMethod() const override {
return new ExampleProduct2();
}
};
// USER CLASS
void User(const Create& create) {
std::cout << "User Method is called\n" << create.SomeOperation() << std::endl;
}
// MAIN FUNCTION
int main() {
std::cout << "App: Launched with the ConcreteCreator1.\n";
Create* create = new ExampleCreator1();
User(*create);
std::cout << std::endl;
std::cout << "App: Launched with the ConcreteCreator2.\n";
Create* create2 = new ExampleCreator2();
User(*create2);
delete create;
delete create2;
return 0;
}
出力:
App: Launched with the ConcreteCreator1.
User Method is called
Client Code{Product 1 is instantiated}
App: Launched with the ConcreteCreator2.
User Method is called
Client Code{Product 2 is instantiated}
この例では、ファクトリ クラス内に 2つの具象クラスが作成され、ファクトリがクラスを呼び出す方法が観察されます。 Concrete_Example
(基本) クラスは、製品とそのインターフェースの多くの実装を提供します。
クラス Concrete_Example
には ExampleProduct1
と ExampleProduct2
の 2つのサブクラスがあり、user
クラスが呼び出したい製品が含まれています。 以下は、特定の実装を持つ Create
(creator) クラスです。ファクトリ メソッドを宣言すると、製品クラスから user
クラスにオブジェクトが渡されます。
サブクラスは、オブジェクトを返し、その目的のためのメソッドを実装するために作成されます。 クラス名は作成されますが、このクラスまたはそのサブクラスに新しいオブジェクトは作成されません。
Create
クラスの主な目的は、ファクトリ メソッドから製品を返すことです。 サブクラスはメソッドをオーバーライドし、新しい実装を製品に追加できます。
SomeOperation
メソッド内で、ファクトリ Concrete_Example
メソッドからのオブジェクトが作成され、オブジェクトは製品への変更を実装するために使用されます。 ファクトリ メソッドをオーバーライドすることで、サブクラスが製品に変更を加えていることがわかります。
ここで使用されるクライアント コードは、クラス create
インスタンスとそのサブクラスを使用してメソッドを呼び出し、オブジェクトの作成から独立させます。 セットアップまたは環境に続いて、アプリケーションは作成者タイプを選択します。
メイン関数は classCreate
を使用して、サブクラス ExampleCreator1()
のオブジェクトを形成します。 このプログラムでは両方のクリエーター メソッドが Create
クラスから作成されたオブジェクトを使用して呼び出され、実装後、作成されたすべてのオブジェクトが破棄されます。