프로그래밍 공부
카테고리
작성일
2023. 5. 5. 12:30
작성자
WDmil
728x90

추상 팩토리 패턴( Abstract Factory Pattern ) 은 객체 생성을 추상화하는 디자인 패턴 중 하나로, 서로 관련된 객체의 집합을 생성하기 위한 인터페이스를 제공한다.

 

이 패턴은 추상화된 팩토리 클래스를 통해 관련된 객체를 생성하며, 각 객체는 추상 클래스나 인터페이스를 상속받아 구현된다. 이를 통해 클라이언트 코드는 실제 객체의 클래스에 대한 정보를 알 필요 없이 추상화된 인터페이스를 통해 객체를 생성할 수 있는 특징이 있다.

 

장점

  1. 유지보수성과 확장성이 높아진다.
    • 클라이언트 코드와 객체 생성코드를 분리하기 때문에 유지보수가 쉬워지고 확장할때 편하다.
  2. 코드 의존성을 낮춘다.
    • 코드 자체를 실제로 추가할 일이 크지 않을 수 있기 때문에, 어떠한 항목에 대하여 자세한 코드를 작성하지 않아도 되어 코드 의존성이 크게 낮아지고, 유연한 코드를 작성할 수 있게된다.
  3. 쉽게 객체생성 코드를 변경할 수 있다.
    • 위 항목에 근거하여, 새로운 구체 클래스를 추가하거나 기존 클래스를 변경하지 않고 객체 생성코드 를 변경할 수 있게된다.

단점

  1. 코드가 복잡해질 수 있다.
    • 다양한 경우의 수를 전부 구현해야 하기 때문에 코드가 의미없이 복잡해질 수 있다.
  2. 인터페이스와 구현클래스의 구현 난이도가 매우높다.
    • 위의 경우에 의거하여 모든 경우의 수를 전부 구현해야 하기 때문에 구현난이도가 매우 높다.

 

#include <iostream>
#include <memory>

// 추상화 클래스 A
class AbstractProductA {
public:
    virtual ~AbstractProductA() {} // 소멸자
    virtual void use() const = 0; // 사용시 0 으로
};

// 구체화 클래스 A1
class ConcreteProductA1 : public AbstractProductA { // class ConcreateProductA1은 AbstractProductA를 상속받는다. 자식클래스
public:
    void use() const override {
        std::cout << "Using ConcreteProductA1" << std::endl;
    }
};

// 구체화 클래스 A2
class ConcreteProductA2 : public AbstractProductA { // class ConcreateProductA1은 AbstractProductA를 상속받는다. 자식클래스
public:
    void use() const override { // 상속받은 use 를 대채한다.
        std::cout << "Using ConcreteProductA2" << std::endl;
    }
};

// 추상 클래스 B
class AbstractProductB {
public:
    virtual ~AbstractProductB() {}
    virtual void consume() const = 0;
};

// 구체화 클래스 B1
class ConcreteProductB1 : public AbstractProductB {
public:
    void consume() const override {
        std::cout << "Consuming ConcreteProductB1" << std::endl;
    }
};

// 구체화 클래스 B2
class ConcreteProductB2 : public AbstractProductB {
public:
    void consume() const override {
        std::cout << "Consuming ConcreteProductB2" << std::endl;
    }
};

// 추상 팩토리
class AbstractFactory {
public:
    virtual ~AbstractFactory() {}
    virtual std::unique_ptr<AbstractProductA> createProductA() const = 0;
    virtual std::unique_ptr<AbstractProductB> createProductB() const = 0;
};

// 구체화 팩토리 1
class ConcreteFactory1 : public AbstractFactory {
public:
    std::unique_ptr<AbstractProductA> createProductA() const override {
        return std::make_unique<ConcreteProductA1>();
    }

    std::unique_ptr<AbstractProductB> createProductB() const override {
        return std::make_unique<ConcreteProductB1>();
    }
};

// 구체화 팩토리 2
class ConcreteFactory2 : public AbstractFactory {
public:
    std::unique_ptr<AbstractProductA> createProductA() const override {
        return std::make_unique<ConcreteProductA2>();
    }

    std::unique_ptr<AbstractProductB> createProductB() const override {
        return std::make_unique<ConcreteProductB2>();
    }
};

// 클라이언트
class Client {
public:
    Client(std::unique_ptr<AbstractFactory> factory)
        : productA(factory->createProductA()), productB(factory->createProductB())
    {}

    void run() const {
        productA->use();
        productB->consume();
    }

private:
    std::unique_ptr<AbstractProductA> productA;
    std::unique_ptr<AbstractProductB> productB;
};

// 사용 예시
int main() {
    std::unique_ptr<AbstractFactory> factory1 = std::make_unique<ConcreteFactory1>();
    std::unique_ptr<AbstractFactory> factory2 = std::make_unique<ConcreteFactory2>();

    Client client1(std::move(factory1));
    Client client2(std::move(factory2));

    client1.run();
    client2.run();

    return 0;
}

위 코드는 추상 팩토리 방법을 기초적으로 구현해 놓은 코드이다.

 

이 코드를 해석해서 동작을 이어보면 다음과 같이 이어지게 된다.

 

main문에서 AbstractFactory 형태의 유니크주소 를 가진 factory1을 생성한다. 그리고 make_unique 를 통해 자식클래스의 ConcreteFactory1을 넣어준다. 이로써

factory1은 AbstractFactory 형식이지만, 실질적으로 자식클래스인 ConcreteFactory1의 형태를 띄게된다.

그 후 Client 형태의 clinet1변수를 선언하고 여기에 factory1의 데이터의 주소 소유권을 연결해주며 생성자에 매개변수로 전달한다.

 

매개변수로 전달받은 ConcreteFactory1은, Client의 생성자에 따라 각각 ConcreteFactory1에 해당하는 값들인
ConcreteProductA1 의 use()와 COncreteProductB1의 consume() 를 가지게된다

 

그 후 client1.run() 을 통해 가지게된 동작부의 주소값에 접속하여 동작을 실행하게 된다.

즉 이러한 추상 팩토리 기법은 인터페이스 -> 생성부 -> 동작부 로 연결되어 코드가 실행되게 된다.

 

Client에서만 생성자를 넣어서 Client에 연결된 데이터의 동작부를 Client에 끌어오게 되는것이다.

728x90

'디자인 패턴' 카테고리의 다른 글

Obserever 옵저버 패턴  (0) 2023.11.14
싱글톤 패턴(Singleton)  (0) 2023.10.10
빌더 패턴(Builder Pattern)  (0) 2023.05.10