[객체 생성 패턴] Chapter 3-1. Abstract Factory Pattern : 패턴 소개

 

✍️ 추상 팩토리 패턴

추상 팩토리 패턴은 여러 관련있는 객체를 만들어주는 인터페이스다.

 

이름에서부터 알 수 있듯 팩토리 메서드 패턴과 굉장히 헷갈린다. "구체적인 팩토리에서 구체적인 인스턴스를 만드는 것" 까진 팩토리 메서드 패턴과 매우 유사하지만 팩토리를 사용하는 초점이 클라이언트쪽에 있다 보니 다른 구조를 띈다.

 

추상 팩토리 패턴의 목적 자체를 이해하면 팩토리 메서드와 완전히 분리해서 이해할 수 있는데, 추상 팩토리 패턴은 클라이언트 코드에서 팩토리로부터 객체(제품)를 생성하고 사용하는 코드를 인터페이스 기반으로 작성할 수 있게끔 한다.

 

말로만 이해하긴 조금 어려우니 팩토리 메서드 패턴과 추상 팩토리 패턴을 잘 비교한 Stackoverflow의 글 하나를 첨부하려 한다. 예시도 굉장히 이해하기 쉽다. 팩토리 메서드 패턴 vs 추상 팩토리 패턴 

간략하게 의역해 보면 팩토리 메서드 패턴의 핵심은 제품(객체)을 생성하는 추상 메서드와 이를 오버라이드해 필요한 제품을 생성하는 메서드 그 자체라고 볼 수 있고 추상 팩토리 패턴은 제품(객체)을 생성하는 한 개 이상의 추상 메서드를 가진 인터페이스와 이를 구현한 콘크리트 팩토리의 객체에 초점이 맞춰져 있다. 정도로만 해석하면 되지 않을까 싶다.

 

🍊 추상 팩토리 패턴, 적용 전 코드

참고, 본 포스팅의 코드는 이전에 작성했던 팩토리 메서드 패턴의 코드를 알고 있어야 이해하기 쉽습니다.

[객체 생성 패턴] Chapter 2-1. Factory Method Pattern : 패턴 소개

 

기본적으로 Ship에 name, color, logo만 존재했는데 AnchorEngine 속성이 추가됐다.

public class Ship {
    // 편의상 한정자를 public으로
    public String name;
    public String color;
    public String logo;

    // 새로운 속성이 추가됐다!
    // 마찬가지로 편의상 한정자를 public으로
    public Anchor anchor;
    public Engine engine;

    @Override
    public String toString() {
        return "Ship{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", logo='" + logo + '\'' +
                '}';
    }
}
public class Anchor {
}

public class Engine {
}

public class TurtleAnchor extends Anchor {
}

public class TurtleEngine extends Engine {
}

 

그리고 Ship을 상속받는 Turtleship이 있다.

public class Turtleship extends Ship{
    public Turtleship() {
        name = "turtleship";
        logo = "\uD83D\uDC22";
        color = "green";
    }
}

 

 

어디선가 새로 추가된 속성에 값을 할당해야 하는데, 일단은 TurtleShipFactory에서 구체적인 인스턴스를 주입하기로 하자. 

public class TurtleshipFactory implements ShipFactory {
    @Override
    public Ship createShip() {
        Ship ship = new Turtleship();
        ship.anchor = new TurtleAnchor();
        ship.engine = new TurtleEngine();
    }
}

 

여기까진 아무 문제가 없어 보인다. 그러나 시간이 지나 기술이 발달함에 따라 거북선 엔진이 발전하고 닻의 안정성이 개선돼 TurtleGoodAnchor, TurtleGoodEngine이 생겨났다.   

public class TurtleGoodAnchor extends Anchor {
}

public class TurtleGoodEngine extends Engine {
}

 

이제부터 난관에 빠지는데, 새로운 버전의 엔진과 닻이 추가되면 최신형 거북선을 만들기 위해 createGreatShip 메서드를 인터페이스에 추가해야 하고 그 순간 ShipFactory를 구현한 모든 구현체는 해당 메서드를 오버라이드 하라며 에러를 뱉어낼 것이다. Java8기준 default 메서드를 사용하면 되지만 오직 TurtleshipFactory에서만 사용될 추상 메서드가 인터페이스에 추가되는 건 바람직하지 못하다.

public class TurtleshipFactory implements ShipFactory {
    @Override
    public Ship createShip() {
        Ship ship = new Turtleship();
        ship.anchor = new TurtleAnchor();
        ship.engine = new TurtleEngine();

        return ship;
    }

    @Override
    public Ship createGoodShip(){
        Ship ship = new Turtleship();
        ship.anchor = new TurtleGoodAnchor();
        ship.engine = new TurtleGoodEngine();
        
        return ship;
    }
}

 

🤔 정리

바로 이러한 문제를 해결하고자 추상 팩토리 패턴이 등장하게 되었으니... 추상 팩토리 패턴을 적용한 코드는 포스팅에서 소개하겠읍니다. 

 

인프런의 백기선님의 강의 코딩으로 학습하는 GoF의 디자인 패턴을 참고해서 작성했습니다.

 

코딩으로 학습하는 GoF의 디자인 패턴 - 인프런 | 강의

디자인 패턴을 알고 있다면 스프링 뿐 아니라 여러 다양한 기술 및 프로그래밍 언어도 보다 쉽게 학습할 수 있습니다. 또한, 보다 유연하고 재사용성이 뛰어난 객체 지향 소프트웨어를 개발할

www.inflearn.com