C++ ファクトリ メソッド

Jay Shaw 2023年10月12日
  1. C++ のファクトリ メソッド
  2. C++ の単純なコンストラクター クラス
  3. C++ のコンストラクター クラスにファクトリー メソッドを使用する
  4. C++ の具象クラスと抽象ファクトリ メソッド
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_mmFour_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 には ExampleProduct1ExampleProduct2 の 2つのサブクラスがあり、user クラスが呼び出したい製品が含まれています。 以下は、特定の実装を持つ Create(creator) クラスです。ファクトリ メソッドを宣言すると、製品クラスから user クラスにオブジェクトが渡されます。

サブクラスは、オブジェクトを返し、その目的のためのメソッドを実装するために作成されます。 クラス名は作成されますが、このクラスまたはそのサブクラスに新しいオブジェクトは作成されません。

Create クラスの主な目的は、ファクトリ メソッドから製品を返すことです。 サブクラスはメソッドをオーバーライドし、新しい実装を製品に追加できます。

SomeOperation メソッド内で、ファクトリ Concrete_Example メソッドからのオブジェクトが作成され、オブジェクトは製品への変更を実装するために使用されます。 ファクトリ メソッドをオーバーライドすることで、サブクラスが製品に変更を加えていることがわかります。

ここで使用されるクライアント コードは、クラス create インスタンスとそのサブクラスを使用してメソッドを呼び出し、オブジェクトの作成から独立させます。 セットアップまたは環境に続いて、アプリケーションは作成者タイプを選択します。

メイン関数は classCreate を使用して、サブクラス ExampleCreator1() のオブジェクトを形成します。 このプログラムでは両方のクリエーター メソッドが Create クラスから作成されたオブジェクトを使用して呼び出され、実装後、作成されたすべてのオブジェクトが破棄されます。

関連記事 - C++ Method