E D R , A S I H C RSS

DPSC Chapter3

Abstract Factory(31)


ABSTRACT FACTORY(DP 87)


Intent

연관된 혹은 의존적인 객체들의 집합을 만들기 위한 인터페스를 제공한다. 클라언트가 구체적인 클래스들에 대한 구체화
를 하지 않고 추상적으로 어떤 상품의 집합(여러 종류의 자동차들)에서 상품(자동차)을 만든다고 하자.

Discussion

패턴은 실제로 아주 간단하다. 문제 상황은 많은 부분들을 포함한다. Abstract Factory 패턴 적용될 수 있는 예제를 보도록
하자.

우선 첫째로, 우리는 컴포넌트의 하위 부분들로 부터 단계별로 상품(자동차)을 만들 필요가 있는 응용 프로그램을 만들어보자.
그것은 몸체, 엔진, 변속장치, 그리고 승객 칸막을 포함하는 자동차를 만드는 것다. 둘째로, 응용 프로그램은 같은 상품의
부분들을 원한다. 즉 Ford 자동차는 Ford 엔진과 변속장치를 가져야한다. 것은 Ford Family안의 부분들다. 셋째, 우리는
여러 part의 family들을 가진다.
Ford parts,Toyota parts,Porsche parts 등등다. 유사한 클래스들 클래스 구조를 통해서 확장된다. 각각 적당한 하위
구조를 가지게 된다. 가령 CarEngine 하위 구조의 엔진들, CarBody 구조의 body 등등을 가지게 된다.
(결국, 각각 CarEngine을 Base Class로 해서 상속을 통해 Ford Engine,Toyota Engine등등으로 확장될 수 있다는 말다.)
따라서, 우리는 다른 집합의 부분들을 선택하지 않고, 하나의 집합(Family)으로부터 각각의 자동차 부분들을 쉽게 얻을 수
있는 방법 필요하다. (Toyota 엔진에서는 Ford 자동차가 작동할 수 없다.)
그리고 모든 faimily에서 같은 코드를 사용해서 부분들을(엔진,변속장치..) 얻는 것을 사용한다.
우리는 Abstract Factory Pattern을 용해서 두가지 목표를 룰 수 있다.
(정리 : Abstract Factory Pattern은 Factory Pattern을 추상화시킨 것다.Factory Pattern의 목적 Base Class로부터 상속
된 여러 종류의 클래스들 중 하나를 선택할 수 있도록 해주는 것을 의미한다.
Abstract Factory Pattern는 여러 개의 Factory중 하나를 선택할 수 있도록 해주는 것을 수행한다. )
우리는 아래와 같은 자동차와 자동차 부분들의 클래스를 가지고 있다.


Vechile과 CarPart는 Object 클래스의 서브 클래스다. 물론, 클래스 구조는 많은 단계에서 전체적으로 단순화된다.
자동차 회사들(Ford)은 자동차, 몸체, 엔진, 심지어 엔진 종류(가솔린 엔지 혹은 디젤 엔진)도 몇몇 다른 모델을 가지고 있다.
그러므로 우리가 여기서 보여주는 것 보다 현실 세계는 좀더 높은 추상을 가지고 있을 것다. 하지만, 우리의 패턴 묘사를
적용하기에는 충분한 수준의 추상을 제공하고 있다.

우리는 CarPartFactory라는 추상 팩토리 클래스 정의를 하면서 패턴 구현을 시작한다. 것은 "구체적인 클래스들에 대한
구체화 없 관계된 혹은 의존적인 객체 집합을 만들기 위한 인터페스를 제공하는" (Intent 부분에서 언급한 내용)
클래스다. 그것은 추상적인 상품 생성 함수들(makeCar,makeEngine,makeBody)을 정의한다. 그 때 우리는 상품 집합 당
하나의 구체적인 팩토리 하위 클래스를 정의한다. 각각의 하위 클래스들은 적당한 부분을 만들고 반환하기 위해서 상품 생성
함수를 재 정의한다. 그래서 우리는 Object를 상속한 새로운 하위 구조를 추가한다.



자동차 부분(part) 생성 메쏘드를 구현하기 위해서, 우리는 추상 팩토리 클래스로 시작한다.

      CarPartFactory>>makeCar
          self subclassResponsibility

      CarPartFactory>>makeEngine
          self subclassResponsibility

      CarPartFactory>>makeBody
          self subclassResponsibility
그리고 메쏘드를 오버라드하는 구체적인 하위 클래스를 추가한다.

      
      FordFactory>>makeCar
          ^FordCar new

      FordFactory>>makeEngine
          ^FordEngine new

      FordFactory>>makeBody
          ^FordBody new

      ToyotaFactory>>makeCar
          ^ToyotaCar new

      ToyotaFactory>>makeEngine
          ^ToyotaEngine new

      ToyotaFactory>>makeBody
          ^ToyotaBody new
전체적으로, 우리의 팩토리들은 아래와 같 보인다.


Abstract Factory로, 부분들을(part) 결합시키는 것은 팩토리의 클라언트가 하는 일다. 팩토리는 부분들의(part) 하나의 집합의 (family)로 부터 나온다는 것을 보장한다. 하지만, 팩토리는 단지 부분을(part) 반환하는 일만 할 뿐다. 최종 상품은 팩토리가 조립하지 않는다. 그것은 클라언트의 일다. (우리는 Abstract Factory와 Builder 패턴 사의 주요한 차점을 나중에 볼 것다.)

CarAssembler 객체가 팩토리 클라언트라고 추정해보자. 그리고 CarPartFactory 객체를 참조하는 팩토리라고 름지어진 인스턴스 변수를 갖자.

    
         CarAssembler>>assembleCar
             | car |
             "Create the top-level part, the car object which starts out having no subcomponents, and add an engine, body, etc."
             
             car := factory makeCar
             car 
                 addEngine: factory makeEngine;
                 addBody: factory makeBody;
                 ...
             ^car
만약, 팩토리가 FordFactory의 인스턴스였다면, 자동차에 추가되기 위해 얻어진 엔진은 FordEngine일 것다. 만약 팩토리가 ToyotaFactory였다면, ToyotaEngine은 팩토리의 makeEngine에 의해서 만들어 질 것고, 그 때 자동차에 추가될 것다.

아직, 확실하지 않는 한 부분 있다. CarAssembler는(factory 클라언트) 어떻게 구체적인 CarPartFactory 하위 클래스의 인스턴스를 얻을 수 있을까? 그것은 특별한 하위 클래스 자체를 소비자의 선택에 기초해서 인스턴스화 할 수 있을 것다. 혹은 외부 객체에 의해서 팩토리 인스턴스를 다룰수도 있을 것다.
하지만, 두 경우에 자동차를 생성하기 위한 코드와 그것의 컴포넌트 하위 부분은 여전히 같다. 즉, 모든 CarPartFactory 클래스들은 동일한 메시지 프로토콜을(다형성)을 구현하기 때문에, 팩토리 클라언트는 팩토리 타입 무엇인지 상관하지 않고 호출을 할 수 있다. 그것은 단지 팩토리 프로토콜에 의해 제공되는 일반적인 메시지를 전송한다.

다형성의 힘 때문에, 클라언트는 코드 구현을 한번만 하면된다. ABSTRACT FACTORY PATTERN을 사용하지 않을 경우, 자동차 생성 코드는 다음과 같 보일 것다.(아주 비효율적인 코드)

         CarAssembler>>assembleCar
            "Without Abstract Factory."
            | car |
            car := (consumerChoice == #Ford
                       ifTrue:  [FordCar new]
                       ifFalse:  [consumerChoice == #Toyota
                           ifTrue:  [ToyotaCar new]
                           ifFalse:  [consumerChoice == #Porsche
                                  ifTrue:  [PorscheCar new]
                                  ifFalse:  [...])
            car addEngine:
                   (consumerChoice == #Ford
                       ifTrue:  [FordEngine new]
                       ifFalse:  [...]).
           
            ...
            ^car
따라서, CarAssmebler를 만들기 위한 자동차 종류가 무엇고 그 하위 부분들 무엇을 해야하고, 그것의 실제 부분의 인스턴스가 무엇을 수행해야 할지를 결정한다. ABSTRACT FACTORY 해결은 우리가 CarAssembler 객체 밖의 모든 행동들을 추상화시킨다. 그리고 팩토리로 분리한다. 특별한 자동차 팩토리로 CarAssembler 확인을 한 후에, CarAssembler는 간단하게 구체적인 자동차와 하위 부분을 만들기 위한 팩토리를 호출한다.

ABSTRACT FACTORY 접근은 좀더 모듈적고, 좀더 쉽게 확장 가능한 디자인을 할 수 있다. 시스템에 새로운 타입의 자동차를 추가하기 위해서, 우리는 CarPartFactory의 서브 클래스를
추가하고 그것을 인스턴스화기 위한 코드가 필요할 뿐다.

여기에 효과적인 두 개의 추상 있다. 첫번째, 모든 CarPartFactory 같은 메시지 인터페스를 구현한다. 클라언트가 그들 메시지를 보내기 위해서 CarPartFactory의 정확한
타입 무엇인지 신경쓰지 않고 같은 생성 메시지를 보내는 것을 팩토리가 수행한다.
Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:23:04
Processing time 0.0495 sec