디자인 패턴

추상 팩토리 패턴(1) - 개념, 패턴 적용하기

깊게 생각하고 최선을 다하자 2022. 9. 2. 02:00

1) 추상 팩토리 패턴이란?

- 추상 팩토리는 관련 있는 여러 인스턴스를 만들어주는 팩토리를 추상화된 형태로 정의하는 패턴입니다. 

  그래서 구체적인 팩토리에서 구체적인 인스턴스를 만드는 것까지는 팩토리 메소드 패턴과 매우 비슷하지만,

  초점이 클라이언트 쪽에 있습니다. 

 

- 추상 팩토리 패턴의 목적 자체가 클라이언트 코드를 인터페이스 기반으로 할 수 있게끔 도와주는 것입니다. 

  모양은 팩토리 쪽에서 보면 팩토리 메소드 패턴과 매우 비슷하지만,

  팩토리를 사용하는 쪽 코드와 같이 봐야 합니다. 

 

- 이전에 살펴봤던 패턴에 비해 클라이언트만 추가되었고, 

  내부 구조는 팩토리 메소드 패턴과 매우 비슷합니다. 

 

 

2) 패턴 적용하기

- 이 클래스는 클라이언트 코드에 해당합니다.

  클라이언트 코드를 보면 구체적인 클래스 타입(ex) new WhiteAnchor(), new WhiteWheel())

  에 의존하고 있음을 볼 수 있습니다.

  이 때, 할 일은 비슷한 류의 제품군을 만드는 인터페이스를 정의하는 것입니다. 

public class WhiteshipFactory extends DefaultShipFactory{

   @Oveerride
   public Ship createShip(){
       Ship ship = new Whiteship();
       ship.setAnchor(new WhiteAnchor());
       ship.setWheel(new WhiteWheel());
       return ship;
   }
}

- ShipPartsFactory라는 추상 팩토리를 만들 수 있습니다.

  Anchor와 Wheel도 각각 인터페이스를 만들었습니다. 

public interface ShipPartsFactory {
    Anchor createAnchor();
    Wheel createWheel();
}
public interface Anchor{
}
public interface Wheel{
}

- 그리고 추상 팩토리의 구체적인 팩토리인 WhiteshipPartsFactory를 만들 수 있습니다.   

public class WhiteshipPartsFactory implements ShipPartsFactory{
    @Override
    public Anchor createAnchor(){
        return new WhiteAnchor();
    }
    
    @Override
    public Wheel createWheel(){
        return new WhiteWheel();
    }
}

- WhiteAnchor와 WhiteWheel은 각각의 제품군에 해당하는 인터페이스를 구현해야 합니다.

  그래야만 그 제품의 특징을 가질 수 있습니다. 

public class WhiteAnchor implements Anchor{
}
public class WhiteWheel implements Wheel{
}

- 그 다음 ShipPartsFactory를 주입 받아서, Anchor와 Wheel을 생성해줍니다. 

public class WhiteshipFactory extends DefaultShipFactory{

   private ShipPartsFactory shipPartsFactory;
   
   public WhiteshipFactory(ShipPartsFactory shipPartsFactory){
      this.shipPartsFactory = shipPartsFactory;
   }

   @Oveerride
   public Ship createShip(){
       Ship ship = new Whiteship();
       ship.setAnchor(shipPartsFactory.createAnchor());
       ship.setWheel(shipPartsFactory.createWheel());
       return ship;
   }
}

- 이제 Pro 제품을 만들고 싶다면 다음과 같이 하면 됩니다. 

public class WhitePartsProFactory implements ShipPartsFactory{
      
      @Override
      public Anchor createAnchor(){
          return new WhiteAnchorPro();
      }
      
      @Override
      public Anchor createWheel(){
         return new WhieWheelPro();
      }
}
public WhiteAnchorPro implements Anchor{
}
public WhiteWheelPro implements Wheel{
}

- 이제 ShipInventory에서 ShipFactory를 WhitePartsProFactory를 통해서 만들 수 있습니다.

  혹은 WhitePartsProFactory를 WhiteshipPartsFactory로 교체할 수도 있습니다. 

  이 때, WhiteshipFactory 자체는 바뀌지 않습니다.  

public class ShipInventory{

   public static void main(String[] args){
       ShipFactory shipFactory = new WhiteshipFactory(new WhitePartsProFactory());
       Ship ship = shipFactory.createShip();
       System.out.println(ship.getAnchor().getClass());
       System.out.println(ship.getWheel().getClass());
   }
}

 

- 이 때, ShipPartsFactory는 일종의 SRP를 지켰다고 볼 수도 있지만,

   또 다른 관점으로는 여러 가지 제품을 받으므로 SRP를 위반한거 아니냐라고 볼 수도 있습니다. 

   혹은 WhiteshipFactory가 OCP를 지켰다고 볼 수도 있습니다. 

 

 

참고

- 백기선 코딩으로 학습하는 GoF의 디자인 패턴