추상 팩토리

마음이편해·2022년 12월 19일
0

추상팩토리

  • 추상팩토리란?
    : 추상 팩토리는 관련 객체들의 구상 클래스들을 지정하지 않고도 관련 객체들의 모음을 생성할 수 있도록 하는 디자인패턴

추상팩토리의 팩토리는 추상화된 객체의 모음을 생성할수 있도록 하는 인터페이스

추상팩토리는 다른카테고리을 하나의 추상화된 개념으로 묶는 방식으로 생성하는 패턴이라고 볼 수 있다.

  • ex) 흔히접하는 RPG게임에서의 각기 다른 카테고리(검, 갑옷, 신발, 장갑 등)을 하나로 묶는(게임에서의 장비 세트효과[던파 아바타세트, 장비세트 등])개념이다.

클라이언트가 해당되는 추상팩토리를 사용하게 된다면, 팩토리의 클래스들을 알 필요가 없으며, 팩토리가 어떤 변형의 장비 세트를 생성할지 전혀 신경쓸필요 또한 없다. 클라이언트는 추상 Sword(검) 인터페이스를 사용하여, 어떤 검 종류에 상관없이 모든 검을 동일한 방식으로 구현하며, 클라이언트가 하는 유일한 사실은 검이 Attack(공격) 메서드를 구현했다는 것 뿐이다.

  • 추상팩토리의 구현방식

1) 추상 제품들은 제품 패밀리를 구성하는 개별 연관 제품들의 집합에 대한 인터페이스들을 선언한다.
2) 구상 제품들은 변형들로 그룹화된 추상 제품들의 다양한 구현, 각 추상 제품​(의자/소파)​은 주어진 모든 변형​(빅토리안/현대식)​에 구현되어야 한다.
3) 추상 팩토리 인터페이스는 각각의 추상 제품들을 생성하기 위한 여러 메서드들의 집합을 선언한다.
4) 구상 팩토리들은 추상 팩토리의 생성 메서드들을 구현, 각 구상 팩토리는 제품들의 특정 변형들에 해당하며 해당 특정 변형들만 생성한다.
5) 구상 팩토리들은 구상 제품들을 인스턴스화하나, 그 제품들의 생성 메서드들의 시그니처들은 그에 해당하는 추상 제품들을 반환해야 한다. 그래야 팩토리를 사용하는 클라이언트 코드가 팩토리에서 받은 제품의 특정 변형과 결합되지 않는다. 클라이언트는 추상 인터페이스를 통해 팩토리/제품 변형의 객체들과 소통하는 한 그 어떤 구상 팩토리/제품 변형과 작업할 수 있다.

  • 예제코드
/**
 * Each distinct product of a product family should have a base interface. All
 * variants of the product must implement this interface.
 */
class AbstractProductA {
 public:
  virtual ~AbstractProductA(){};
  virtual std::string UsefulFunctionA() const = 0;
};

/**
 * Concrete Products are created by corresponding Concrete Factories.
 */
class ConcreteProductA1 : public AbstractProductA {
 public:
  std::string UsefulFunctionA() const override {
    return "The result of the product A1.";
  }
};

class ConcreteProductA2 : public AbstractProductA {
  std::string UsefulFunctionA() const override {
    return "The result of the product A2.";
  }
};

/**
 * Here's the the base interface of another product. All products can interact
 * with each other, but proper interaction is possible only between products of
 * the same concrete variant.
 */
class AbstractProductB {
  /**
   * Product B is able to do its own thing...
   */
 public:
  virtual ~AbstractProductB(){};
  virtual std::string UsefulFunctionB() const = 0;
  /**
   * ...but it also can collaborate with the ProductA.
   *
   * The Abstract Factory makes sure that all products it creates are of the
   * same variant and thus, compatible.
   */
  virtual std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const = 0;
};

/**
 * Concrete Products are created by corresponding Concrete Factories.
 */
class ConcreteProductB1 : public AbstractProductB {
 public:
  std::string UsefulFunctionB() const override {
    return "The result of the product B1.";
  }
  /**
   * The variant, Product B1, is only able to work correctly with the variant,
   * Product A1. Nevertheless, it accepts any instance of AbstractProductA as an
   * argument.
   */
  std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const override {
    const std::string result = collaborator.UsefulFunctionA();
    return "The result of the B1 collaborating with ( " + result + " )";
  }
};

class ConcreteProductB2 : public AbstractProductB {
 public:
  std::string UsefulFunctionB() const override {
    return "The result of the product B2.";
  }
  /**
   * The variant, Product B2, is only able to work correctly with the variant,
   * Product A2. Nevertheless, it accepts any instance of AbstractProductA as an
   * argument.
   */
  std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const override {
    const std::string result = collaborator.UsefulFunctionA();
    return "The result of the B2 collaborating with ( " + result + " )";
  }
};

/**
 * The Abstract Factory interface declares a set of methods that return
 * different abstract products. These products are called a family and are
 * related by a high-level theme or concept. Products of one family are usually
 * able to collaborate among themselves. A family of products may have several
 * variants, but the products of one variant are incompatible with products of
 * another.
 */
class AbstractFactory {
 public:
  virtual AbstractProductA *CreateProductA() const = 0;
  virtual AbstractProductB *CreateProductB() const = 0;
};

/**
 * Concrete Factories produce a family of products that belong to a single
 * variant. The factory guarantees that resulting products are compatible. Note
 * that signatures of the Concrete Factory's methods return an abstract product,
 * while inside the method a concrete product is instantiated.
 */
class ConcreteFactory1 : public AbstractFactory {
 public:
  AbstractProductA *CreateProductA() const override {
    return new ConcreteProductA1();
  }
  AbstractProductB *CreateProductB() const override {
    return new ConcreteProductB1();
  }
};

/**
 * Each Concrete Factory has a corresponding product variant.
 */
class ConcreteFactory2 : public AbstractFactory {
 public:
  AbstractProductA *CreateProductA() const override {
    return new ConcreteProductA2();
  }
  AbstractProductB *CreateProductB() const override {
    return new ConcreteProductB2();
  }
};

/**
 * The client code works with factories and products only through abstract
 * types: AbstractFactory and AbstractProduct. This lets you pass any factory or
 * product subclass to the client code without breaking it.
 */

void ClientCode(const AbstractFactory &factory) {
  const AbstractProductA *product_a = factory.CreateProductA();
  const AbstractProductB *product_b = factory.CreateProductB();
  std::cout << product_b->UsefulFunctionB() << "\n";
  std::cout << product_b->AnotherUsefulFunctionB(*product_a) << "\n";
  delete product_a;
  delete product_b;
}

int main() {
  std::cout << "Client: Testing client code with the first factory type:\n";
  ConcreteFactory1 *f1 = new ConcreteFactory1();
  ClientCode(*f1);
  delete f1;
  std::cout << std::endl;
  std::cout << "Client: Testing the same client code with the second factory type:\n";
  ConcreteFactory2 *f2 = new ConcreteFactory2();
  ClientCode(*f2);
  delete f2;
  return 0;
}

실행결과

Client: Testing client code with the first factory type:
The result of the product B1.
The result of the B1 collaborating with the (The result of the product A1.)

Client: Testing the same client code with the second factory type:
The result of the product B2.
The result of the B2 collaborating with the (The result of the product A2.)

0개의 댓글