팩토리패턴

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

팩토리패턴

  • 팩토리패턴이란?
    : 부모 클래스에서 객체들을 생성할 수 있는 인터페이스를 제공하지만, 자식 클래스들이 생성될 객체들의 유형을 변경할 수 있도록 하는 생성 패턴

하나의 클래스 혹은 인터페이스에대해 종속성이 강한 코드에서 종류는 비슷하지만 내부 구현은 다른 코드가 추가되어야 한다면 유용하게 사용할 수 있는 디자인패턴이다.

  • ex) 물류관리의 코드에서 물류관리에 관한 대부분의 코드가 운송수단인 Truck클래스에 종속성일 경우 해상 물류의 회사에서 Ship 선박코드를 추가해달라고 할 경우

팩토리패턴 구현방식

  • 객체 생성(new 등)에 관한 메서드는 팩토리 메서드에 대한 호출로 대체하는 것
    구현방식에 대한 제약사항에는 팩토리 메서드에서 생성되는 객체들이 공통된 인터페이스를 가지고 있어야 함


    위의 그림은 생성메서드인 RoadLogistics, SeaLogistics와 공통인터페이스인 deliver를 구현해야함

구조


1. 제품(Product클래스)는 인터페이스를 선언.
2. ConcreteProduct(x)는 Product클래스의 구현방식의 종류이다.
3. 생성(Creator)클래스는 Product구현별 객체들을 반환하는 팩토리 메서드를 선언함.

  • 주석
    당신은 팩토리 메서드를 abstract​(추상)​로 선언하여 모든 자식 클래스들이 각각 이 메서드의 자체 버전들을 구현하도록 강제할 수 있으며, 또 대안적으로 기초 팩토리 메서드가 디폴트​(기본값) 제품 유형을 반환하도록 만들 수도 있습니다.
    크리에이터라는 이름에도 불구하고 크리에이터의 주책임은 제품을 생성하는 것이 아닙니다. 일반적으로 크리에이터 클래스에는 이미 제품과 관련된 핵심 비즈니스 로직이 있으며, 팩토리 메서드는 이 로직을 구상 제품 클래스들로부터 디커플링​(분리) 하는 데 도움을 줄 뿐입니다. 대규모 소프트웨어 개발사에 비유해 보자면, 이 회사는 프로그래머들을 위한 교육 부서가 있을 수 있으나, 회사의 주 임무는 프로그래머를 교육하는 것이 아니라 코드를 작성하는 것입니다.
  1. 구상 크리에이터들은 기초 팩토리 메서드를 오버라이드​(재정의)​하여 다른 유형의 제품을 반환하게 하도록 한다.
    참고로 팩토리 메서드는 항상 새로운 인스턴스들을 생성해야 할 필요가 없다.
    팩토리 메서드는 기존 객체들을 캐시, 객체 풀 또는 다른 소스로부터 반환할 수 있습니다.( ...??)
  • 예제코드
/**
 * The Product interface declares the operations that all concrete products must
 * implement.
 */

class Product {
 public:
  virtual ~Product() {}
  virtual std::string Operation() const = 0;
};

/**
 * Concrete Products provide various implementations of the Product interface.
 */
class ConcreteProduct1 : public Product {
 public:
  std::string Operation() const override {
    return "{Result of the ConcreteProduct1}";
  }
};
class ConcreteProduct2 : public Product {
 public:
  std::string Operation() const override {
    return "{Result of the ConcreteProduct2}";
  }
};

/**
 * The Creator class declares the factory method that is supposed to return an
 * object of a Product class. The Creator's subclasses usually provide the
 * implementation of this method.
 */

class Creator {
  /**
   * Note that the Creator may also provide some default implementation of the
   * factory method.
   */
 public:
  virtual ~Creator(){};
  virtual Product* FactoryMethod() const = 0;
  /**
   * Also note that, despite its name, the Creator's primary responsibility is
   * not creating products. Usually, it contains some core business logic that
   * relies on Product objects, returned by the factory method. Subclasses can
   * indirectly change that business logic by overriding the factory method and
   * returning a different type of product from it.
   */

  std::string SomeOperation() const {
    // Call the factory method to create a Product object.
    Product* product = this->FactoryMethod();
    // Now, use the product.
    std::string result = "Creator: The same creator's code has just worked with " + product->Operation();
    delete product;
    return result;
  }
};

/**
 * Concrete Creators override the factory method in order to change the
 * resulting product's type.
 */
class ConcreteCreator1 : public Creator {
  /**
   * Note that the signature of the method still uses the abstract product type,
   * even though the concrete product is actually returned from the method. This
   * way the Creator can stay independent of concrete product classes.
   */
 public:
  Product* FactoryMethod() const override {
    return new ConcreteProduct1();
  }
};

class ConcreteCreator2 : public Creator {
 public:
  Product* FactoryMethod() const override {
    return new ConcreteProduct2();
  }
};

/**
 * The client code works with an instance of a concrete creator, albeit through
 * its base interface. As long as the client keeps working with the creator via
 * the base interface, you can pass it any creator's subclass.
 */
void ClientCode(const Creator& creator) {
  // ...
  std::cout << "Client: I'm not aware of the creator's class, but it still works.\n"
            << creator.SomeOperation() << std::endl;
  // ...
}

/**
 * The Application picks a creator's type depending on the configuration or
 * environment.
 */

int main() {
  std::cout << "App: Launched with the ConcreteCreator1.\n";
  Creator* creator = new ConcreteCreator1();
  ClientCode(*creator);
  std::cout << std::endl;
  std::cout << "App: Launched with the ConcreteCreator2.\n";
  Creator* creator2 = new ConcreteCreator2();
  ClientCode(*creator2);

  delete creator;
  delete creator2;
  return 0;
}
  • 실행결과
App: Launched with the ConcreteCreator1.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct1}
App: Launched with the ConcreteCreator2.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct2}

0개의 댓글