C++ 팩토리 메서드

Jay Shaw 2023년10월12일
  1. C++의 팩토리 메소드
  2. C++의 단순 생성자 클래스
  3. C++의 생성자 클래스에 팩토리 메서드 사용
  4. C++의 구체적인 클래스 및 추상 팩토리 메서드
C++ 팩토리 메서드

팩토리 메서드는 사용자가 메서드 호출을 보지 않고 인터페이스를 사용할 수 있도록 구성을 숨기면서 개체를 만드는 데 사용되는 C++의 개체 생성 디자인 패턴입니다.

C++의 팩토리 메소드

팩토리는 프로그래머가 사용자가 깨끗한 프로그램 인터페이스와 상호 작용할 수 있는 프로그램을 설계할 수 있게 해주는 가상 생성자입니다. 이는 부모 클래스 내부에 개체 생성 자체를 숨기는 것을 의미합니다.

프로그램에 부모 클래스와 사용자 하위 클래스의 두 클래스가 있는 경우 생성자를 사용하면 두 클래스가 서로 크게 의존하게 됩니다. 상위 클래스 내부에서 변경이 유발되면 하위 클래스의 후속 변경으로 이어집니다.

Factory의 기능은 프로그램 시작 시 객체를 명시하고 새 객체를 추가하는 기능을 여는 기능입니다. 필요한 모든 변경 사항은 다른 곳이 아닌 라이브러리 클래스 내에서만 적용되기 때문입니다.

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_SizesTwo_mmFour_mm이라는 두 개의 하위 클래스가 있는 라이브러리 또는 상위 클래스입니다. 여기서 Diameter() 메서드는 오버로드되고 메서드가 호출될 때 print 문을 반환합니다.

User 클래스에서 매개변수 유형은 main() 함수에서 전달된 값을 가져오고 반환 유형과 일치하는 객체 클래스를 생성합니다. ~User()(소멸자)는 할당된 리소스를 삭제하고 포인터를 지웁니다.

main() 함수는 2 값을 전달하는 동안 *pClient 객체를 생성합니다. 이 값은 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 enum 데이터 안에 처음에 프로그램에서 사용되는 세 개의 개체를 입력합니다.

if-else 조건은 Wire_Sizes(라이브러리) 클래스 바로 뒤에 있는 새 생성자 Create() 내부에 작성됩니다. 새 개체를 추가하는 것이 클라이언트 클래스를 변경하는 것보다 쉽습니다.

생성자는 type 매개변수를 사용하여 값을 가져와 if-else 래더 내에서 일치시킵니다. 일치하는 경우 해당 함수가 호출되고 일치하지 않는 경우 NULL이 반환됩니다.

user 클래스는 개체를 명시적으로 생성하지 않지만 팩토리 메서드 Create()에 유형을 전달합니다. 객체 Size_three_mm는 유형에 전달되고 생성자 클래스 Create()는 할당 연산자를 사용하여 pDiameter에 할당됩니다.

~user()(소멸자)는 클래스 끝에 할당된 리소스를 파괴하고 NULL을 변수 pDiameter에 할당합니다. 생성자 getDiameter 내부에서 변수 pDiameter가 반환됩니다.

main() 메서드는 user 클래스의 개체 *pClient를 생성하고 이 개체를 pDiameter() 메서드라고 합니다. getDiameter() 메서드는 유형 내부에 값이 저장된 pDiameter 변수를 반환합니다.

Wire_Sizes * pDiameter = pClient->getDiameter(); 구문 NULL을 저장하는 pDiametergetDiameter() 메소드의 값을 전달하고 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}

실시간 데모 실행

이 예제에서는 팩토리 클래스 내부에 두 개의 구체적인 클래스가 생성되고 팩토리 호출 클래스가 관찰되는 방식이 표시됩니다. Concrete_Example(기본) 클래스는 제품 및 해당 인터페이스에 대한 많은 구현을 제공합니다.

Concrete_Example 클래스에는 ExampleProduct1ExampleProduct2라는 두 개의 하위 클래스가 있으며 여기에는 user 클래스가 호출하려는 제품이 포함됩니다. 다음은 특정 구현이 포함된 만들기(작성자) 클래스입니다. 팩토리 메서드를 선언하면 제품 클래스에서 사용자 클래스로 개체가 전달됩니다.

객체를 반환하고 해당 목적을 위한 메서드를 구현하기 위해 하위 클래스가 생성됩니다. 클래스 이름이 생성되더라도 이 클래스 또는 하위 클래스에 새 객체가 생성되지 않습니다.

Create 클래스의 주요 목적은 팩토리 메서드에서 제품을 반환하는 것입니다. 하위 클래스는 메서드를 재정의하고 제품에 새 구현을 추가할 수 있습니다.

SomeOperation 메서드 내에서 팩토리 Concrete_Example 메서드의 객체가 생성되고 이 객체는 제품 변경 사항을 구현하는 데 사용됩니다. 하위 클래스가 팩토리 메서드를 재정의하여 제품에 변경을 가하는 것을 볼 수 있습니다.

여기에 사용된 클라이언트 코드는 create 인스턴스 클래스와 해당 하위 클래스를 사용하여 메서드를 호출하여 개체 생성과 독립적으로 만듭니다. 설정 또는 환경에 따라 애플리케이션은 작성자 유형을 선택합니다.

기본 함수는 classCreate를 사용하여 하위 클래스 ExampleCreator1()의 객체를 형성합니다. 두 작성자 메서드는 Create 클래스에서 생성된 개체를 사용하여 이 프로그램에서 호출되며 구현 후 생성된 모든 개체는 소멸됩니다.

관련 문장 - C++ Method