해당 포스트는 "자바 객체지향 디자인 패턴", "JAVA 언어로 배우는 디자인 패턴 입문" 책의 내용을 요약한 것이다.



※추상 팩토리(Abstract Factory) 패턴

: 관련성 있는 어려 종류의 객체를 특정 그룹으로 묶어 한번에 일관된 방식으로 생성하고 교체할 수 있도록 만든 디자인 패턴이다.

예를 들어, 특정 라이브러리를 배포하는 데 OS별로 지원하는 기능이 상이하다면 추상 팩토리 패턴을 사용해 OS별 기능을 통합적으로 변경할 수 있다. 추상 팩토리 패턴은 팩토리 메서드 패턴과 매우 유사하나 팩토리 메서드 패턴은 클래스들이 "create(객체를 생성하는)" 메서드를 구현하고 하나의 객체를 반환하는 게 전부이지만 추상 팩토리 패턴은 클라이언트에 연관된 객체들의 패밀리를 반환하는 것이다.

 

 

ex) 엘리베이터 부품 업체 변경하기

"템플릿 메서드" 패턴 포스트 의 엘리베이터 예제를 보면 LGMotor와 HyundaiMotor의 move 함수에서 대부분의 코드가 같으나 moveMotor() 함수만 달라서 템플릿 메서드 패턴을 이용했다. 여기서 추가적으로 해당 포스트에 나온 Door 클래스의 open()과 close() 메서드 또한 LG나 Hyundai에 따라서 다르다고 가정해 템플릿 메서드 패턴을 적용하였다고 가정하자. 그러면 Door 클래스를 상속 받는 LGDoor 클래스와 HyundaiDoor 클래스가 생기게 된다. 따라서 엘리베이터 입장에서는 특정 제조 업체의 모터와 문을 제어하는 클래스가 필요하다. 예를 들면 LGMotor 객체와 LGDoor 객체가 필요하다. 그래서 객체의 생성 방식을 팩토리 메서드 패턴을 적용하기로 하자.

 

public enum VenderID {LG, HYUNDAI}
public class MotorFactory{
    public static Motor createMotor(VendorID vendorID){
       Motor motor = null;
       switch(vendorID){
           case LG:
             motor = new LGMotor();
             break;
          case HYUNDAI:
             motor = new HyundaiMotor();
             break;
      }
      return motor;
   }
}
public class DoorFactory{
   public static Door createDoor(VendorID vendorID) {
       Door door = null;
       switch(vendorID) {
           case LG:
              door = new LGDoor();
              break;
          case HYUNDAI:
              door = new HyundaiDoor();
      }
     return door;
   }
}
public class Client{
     public static void main(String[] args){
         Door lgDoor = DoorFactory.createDoor(VendorID.LG);
         Motor lgMotor = MotorFactory.createMotor(VendorID.LG);
         lgMotor.setDoor(lgDoor);
         
         lgDoor.open();
         lgMotor.move(Direction.UP);
    }
}

팩토리 메서드 패턴을 사용한다면 위와 같은 코드가 된다.

 

 

- 문제점

LG 엘리베이터 대신 Hyundai 엘리베이터를 사용할 경우 위 예제 main 클래스에서는 코드 첫 번째와 두 번째 줄만 바꾸면 된다. 하지만 엘리베이터가 모터와 문 말고 4개의 램프, 3개의 스피커, 2개의 버튼을 가지고 있다면 각각의 부품마다 팩토리 클래스가 존재할 것이기에 부품 총 수 11줄을 바꿔야 한다. 또한 새로운 제조 업체의 부품을 지원해야 하는 경우, LG와 Hyundai 엘리베이터가 아닌 Samsung 엘리베이터를 지원해야 한다면 각각의 팩토리 클래스의 switch 문 마다 case SAMSUNG: 문을 추가해줘야한다.

 

 

- 해결책

엘리베이터는 Hyundai라면 모든 부품이 Hyundai일 것이다. 이렇게 여러 종류의 객체를 생성할 때 객체들 사이의 관련성이 있는 경우라면 각 종류별로 별도의 Factory 클래스를 사용하는 대신 관련 객체들을 일관성 있게 생성하는 추상 팩토리 패턴을 적용하는 것이 편리하다.

 

public abstract class ElevatorFactory{
    public abstract Motor createMotor();
    public abstract Door createDoor();
}

public class LGElevatorFactory extends ElevatorFactory{
    public Motor createMotor(){
       return new LGMotor();
   }
   public Door createDOor() {
      return new LGDoor();
   }
}

public class HyundaiElevatorFactory extends ElevatorFactory{
    public Motor createMotor(){
       return new HyundaiMotor();
   }
   public Door createDOor() {
      return new HyundaiDoor();
   }
}

제조 업체별로 Factory 클래스를 정의해 제조 업체별 부품 객체를 아주 간단히 생성할 수 있다. 즉, LG 부품을 이용할 때는 LGElevatorFactory객체를 생성할 수 있고 현대의 부품을 이용할 때는 HyundaiElevatorFactory 객체를 생성할 수 있다.

 

public class Client{
     public static void main(String[] args){
        ElevatorFactory factory = null;
        String vendorName = args[0];
        if(vendorName.equalsIgnoreCase("LG")){
             factory = new LGElevatorFactory();
        else
            factory = new HyundaiElevatorFactory();
        Door door = factory.createDoor();
        Motot motor = factory.createMotor();
    }
}

여기서 Factory클래스를 우리가 앞에서 배운 팩토리 메서드 패턴을 적용할 수 있다. 아래 코드가 적용 예이다.

public class ElevatorFactoryFactory{
    public static ElevatorFactory getFactory(VendorID vendorID){
         switch(vendorID){
            case LG:
               factory = new LGElevatorFactory();
           case HYUNDAI:
              factory = new HyundaiElevatorFactory();
           break;
        }
       return factory;
   }
}

public class Client{
      public static void main(String[] args){
          String vendorName = args[0];
          VendorID vendorID;
          if(vendorName.equalsIgnoreCase("LG"))
               vendorID = VendorID.LG;
         else if(vendorName.equalsIgnoreCase("HYUNDAI"))
              vendorID = VendorID.HYUNDAI;

         ElevatorFactory factory = ElevatorFactoryFactory.getFactory(vendorID);
         Door door = factory.createDoor();
         Motor motor = factory.createMotor();
  }
}

팩토리 메서드 패턴 적용 전 후 차이는 별로 없으나 제조 업체별 Factory 객체를 생성하는 방식을 캡슐화 했다는 점이 다르다.


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

팩토리 메서드 패턴  (0) 2017.07.04
템플릿 메서드 패턴  (0) 2017.07.04
중재자(Mediator) 패턴  (0) 2017.07.04
커맨드(Command) 패턴  (0) 2017.07.03
상태(State) 패턴  (0) 2017.07.03

+ Recent posts