본문 바로가기

디자인 패턴

Creational Pattern - Abstract Factory , Builder

 

Creational Pattern이란?

인스턴스를 만드는 절차를 추상화하여 객체의 표현 방법을 시스템과 분리해준다.

특징

  • 시스템이 사용하는 클레스에 대한 구체적인 정보를 캡슐화한다.
  • 어떤 객체가 생성되고 어떤 클래스가 객체를 생성하며 생성 시기를 유연하게 결정되게 해준다.

 

Abstract Factory

목적

상세화된 sub-class를 정의하지 않고 여려 객체를 생성하기 위한 인터페이스 제공

구조

  • AbstractFactory : Product를 생성하는 연산(실행)과 인터페이스 제공
  • ConcreteFactory: 구체적인 Product를 생성하는 연산(정의) 구현
  • AbstractProduct: AbstractFactory가 생성하는 Product가 가져야 하는 인터페이스 제공
  • ConcreteProduct: ConcreteFactory가 생성하는 구체적인 Product가 구현 및 AbstractFactory가 정의하는 인터페이스 구현
  • Client: AbstractFactory와 AbstractProduct를 사용

활용성

  • 객체가 생성되거나 구성: 객체가 나타나는 방식에 상관 없는 시스템을 만들 때(객체가 언제든 바뀔 수 있다.)
  • 여러 제품 중 하나를 선택해서 시스템을 만들고 이걸 나중에 바꿔야 할 수도 있을 때
  • 관련된 제품 객체들이 함께 사용되도록 설계 되었으며, 객체들의 제약을 외부에서도 유지되게 할 때
  • 제품에 대한 클래스 라이브러리 제공 및 인터페이스를 노출 할 때

협력 방법

  • ConcreteFactory 클래스 인스턴스 한개가 런타임에 만들어지며, concrete factory는 제품 객체를 생성. 서로 다른 제품 객체들을 생성하려면 서로 다른 concrete factory가 필요하다.
  • AbstractFactory는 필요한 제품 객체를 생성하는 책임(구현)을 ConcreteFactory sub-class에 맡긴다.

결과

장점

  • 구체적인 클래스 분리
  • 제품군 대체의 편리함
  • 제품 사이의 일관성

단점

  • 새로운 종류의 제품군 제공이 힘들다

구현

  1. AbstractFactory를 Sigleton으로 정의.
  2. AbstractFactory는 제품을 생성하기 위한 인터페이스만 제공하며, 생성한는 방법에 대한 정의는 ConcreteFactory에서 한다.
  3. 확장 가능한 팩토리 정의

예제

AbstractFactory

class StandardFactory{
	public:
		StandardFactory();
		virtual ProductA* MakeProductA() const {return new ProductA}
		virtual ProductB* MakeProductB() const {return new ProductB}
		virtual ProductC* MakeProductC() const {return new ProductC}
		virtual ProductD* MakeProductD(Option* option) const {return new ProductD(option)}
}

AbstractProduct

class StandardProductA{
	public:
		StandardProductA();
		void somethingForA(){
				/* do someting... */
		};
}

class StandardProductB{
	public:
		StandardProductB();
		void somethingForB(StandardProductA* productA){
				/* do someting... */
		};
}

ConcreteProduct

class SpecialProductA : public StandardProductA{
	public:
		SpecialProductA (SpecialFuction specialFunction);
		void somethingForA(){
				specialFunction();
				/* do someting... */
		};
}

class SpecialProductB : public StandardProductB{
	public:
		SpecialProductB (SpecialFuction specialFunction);
		void somethingForB(StandardProductA* productA){
				specialFunction();
				/* do someting... */
		};
}

ConcreteFactory

class SpecialFactory : public StandardFactory {
	public:
		SpecialFactory();
		virtual ProductA* MakeProductA() const {return new ProductA(DoSpecial)}
		virtual ProductB* MakeProductB() const {return new ProductB(DoSpecial)}
		virtual ProductC* MakeProductC() const {return new ProductC}
		virtual ProductD* MakeProductD(Option* option) const {return new ProductD(option)}
	protected:
		Special* DoSpecial() const;
}

Client

Products* CreateProducts(StandardFactory& factory){
	ProductA* productA = factory.MakeProductA();
	ProductB* productB = factory.MakeProductB();
	ProductC* productC = factory.MakeProductC();
	Option* option = new Option();
	ProductD* productD = factory.MakeProductD(option);

	productA->somethingForA();
	productB->somethingForB(productA);
	productC->somethingForC();
	productD->somethingForD();
	.
	.
	.
	return Products;
}

//// just use standard case ////
StadardFactory factory;
Products* products = CreateProducts(factory);

//// special use case ////
SpecialFactory factory;
Products* products = CreateProducts(factory);

 

Builder

목적

복잡한 객체를 생성하는 방법과 표현하는 방법을 정의하는 클래스를 분리하여 생성 절차를 동일하게 한다.

구조

  • Builer: Product 부품을 생성하기 위한 추상 인터페이스 제공
  • ConcreteBuilder: Builder 클래스에 정의된 인터페이스를 구현
  • Director: Builder 인터페이스를 사용하는 객체를 합성
  • Product: 생성할 객체를 표현. 복합 객체의 구성 절차 정의

활용성

  • 복합 객체의 생성 알고리즘의 조립 방법이 독립적일 때
  • 합성 할 객체들의 표현이 서로 다르더라도 생성 절차에서 지원 해야 할 때

협력 방법

  • 사용자는 Director 객체를 생성, 생성한 객체를 Builder 객체로 합성
  • 제품의 일부가 built 될때 Direcor는 Builder에게 통보
  • Builder는 Director의 요청을 처리해서 부품을 추가
  • 사용자는 Builder에서 제품 검색

결과

  • 제품에 대한 내부 표현의 다향성
  • 생성과 표현에 필요한 코드 분리
  • 복합 객체 생성 절차의 세분화

구현

  1. 조합과 구축에 필요한 인터페이스 정의
  2. 제품에 대한 추상클래스 필요 유무 확인
  3. Builder에 있는 메서드는 구현을 제공하지 않음

예제

Builder

class ProductBuilder{
	public:
		virtual void BuildProduct(){}
		virtual void BuildProductItem(){}
		virtual void BuildProductBox(){}
		virtual Products* GetProduct() { return 0 };
	protected:
		ProductsBuilder();
}

ConcreteBuilder

class StandardProductBuilder : public ProductBuilder{
	public:
		StandardProductBuilder(){
			_currentProduct = 0;
		};
		void BuildProduct(){
			_currentProduct = new Product;
		}
        
		void BuildProductItem(){
			Item* item = new Item();
			_currentProduct->AddItem(item);
		}
        
		void BuildProductBox(){
			Box* box = new Box();
			_currentProduct->SetBox(box)
		}
        
		Product* GetProducts() { 
			return _currentProduct 
		}
        
	private:
		Product* _currentProduct;
}

Director

class ProductProvider{
	public:
    
    	/* 다른거 */
		
        Product* CreateProduct(ProductBuilder& builder){
			builder.BuildProduct();
			builder.BuildItem();
			builder.BuildBox();
 			return builder.GetProduct();
        }
}

 

Builder pattern에서 product와 builder를 합쳐서 다음과 같이 할 수도 있다.

class Product{
    public:
        Product(){
                _item = 0;
                _box = 0;
        }
		
        Product* SetItem(Item* item){
		        _item = item;
                return this;
        }
        
        Product* SetBox(Box* box){
                _box = box;
                return this;
        }
        
    private:
        Item* _item;
        Box* _box
}

사용 예시

class ProductProvider{
	public:
    
    	/* 다른거 */
		
        Product* CreateProduct(){
            Product* product = new Product();
            return product->SetItem(new Item)
                          ->SetBox(new Box);
        }
}

 

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

디자인 패턴 기초  (0) 2021.12.08