DesignPatterns

[디자인 패턴] 추상팩토리 (Abstract Factory)

Tommy__Kim 2023. 6. 27. 14:37

추상팩토리 패턴이란?

추상팩토리 패턴은 구체적인 클래스는 지정하지 않은 채, 관련된 객체들을 생성할 수 있는 디자인 패턴입니다.

이야기로 알아보는 추상팩토리

문제상황

가구점을 운영한다고 가정해 보겠습니다.
가구점에서는 크게 Art Deco, Victorian, Modern 테마로 가구를 만들고 있으며, 가구점에서는 의자, 소파, 커피테이블을 만듭니다.

각 가구들은 같은 테마로 구매를 해야 서로 잘 어울리는 느낌이 납니다. 다른 테마로 구매를 하면 서로 잘 어울리지 않아 고객들의 불만이 많습니다.

또한 새 제품 혹은 제품군을 프로그램에 추가 시 기존 코드를 변경하고 싶지 않을 것입니다.
이럴 때 적용 할 수 있는 디자인 패턴입니다.

해결책 1

우선적으로 의자의 경우 인터페이스로 두고, 각 테마마다 이 인터페이스를 구현하도록 설계를 할 수 있습니다.

해결책 2

그런 다음 제품을 생성하는 공정을 인터페이스로 두고, 각 테마마다 이를 구현해 제품을 생성하는 공정을 구체활 할 수 있습니다.

이렇게 테마마다 공정을 분리하게 될 경우, 같은 테마를 가진 제품들을 생성할 수 있다는 장점이 생깁니다.

추상팩토리 구조


[AbstractFactory]

  1. 각 추상 제품을 생성하기 위한 추상메서드들을 선언합니다.

[ConcreteFactory]

  1. 추상 팩토리에서 선언한 추상메서드를 구현합니다.
  2. 이때, 반환 타입은 Abstract Product여야 합니다.

[Abstract Product]

  1. 제품이 가지는 공통된 특성들을 인터페이스화 합니다.

[Concrete Product]

  1. Abstract Product의 구현체입니다.

코드로 알아보는 추상팩토리

GUI를 담당하는 팩토리가 있다고 가정하겠습니다.
GUI에서 간단하게 버튼 그리고 체크박스를 구현하려고 합니다.

Product1 - Button

public interface Button {
    void paint();
}

// --- // 

public class MacOSButton implements Button{
    @Override
    public void paint() {
        System.out.println("MacOSButton.paint");
    }
}

// --- // 

public class WindowsButton implements Button{
    @Override
    public void paint() {
        System.out.println("WindowsButton.paint");
    }
}

OS별로 다른 버튼을 구현하고 있습니다.
보다 간단한 예시를 들기 위해 메서드의 구현은 메서드 명을 출력하는 방식으로 구현했습니다.

Product2 - CheckBox

public interface CheckBox {
    void paint();
}

// --- // 

public class MacOSCheckBox implements CheckBox{
    @Override
    public void paint() {
        System.out.println("MacOSCheckBox.paint");
    }
}

// --- // 

public class WindowsCheckBox implements CheckBox{
    @Override
    public void paint() {
        System.out.println("WindowsCheckBox.paint");
    }
}

OS별로 다른 체크박스를 구현하고 있습니다.
보다 간단한 예시를 들기 위해 메서드의 구현은 메서드 명을 출력하는 방식으로 구현했습니다.

Factory

public interface GUIFactory {
    Button createButton();

    CheckBox createCheckBox();
}

// --- //

public class MacOSFactory implements GUIFactory{
    @Override
    public Button createButton() {
        return new MacOSButton();
    }

    @Override
    public CheckBox createCheckBox() {
        return new MacOSCheckBox();
    }
}

// --- // 

public class WindowsFactory implements GUIFactory{
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public CheckBox createCheckBox() {
        return new WindowsCheckBox();
    }
}

추상 팩토리인 GUIFactory의 경우 Abstract Product를 반환하는 메서드를 추상화하였습니다.
추상 팩토리의 각 구현체에서 팩토리의 특성에 맞는 Concrete Product를 반환해 주고 있습니다.

Application

public class Application {
    private Button button;
    private CheckBox checkBox;

    public Application(GUIFactory factory) {
        button = factory.createButton();
        checkBox = factory.createCheckBox();
    }

    public void paint() {
        button.paint();
        checkBox.paint();
    }
}

Application 코드에서 Abstract Product에 의존하고 있으며, 생성과 관련된 책임은 추상 팩토리에게 맡기는 것을 확인할 수 있습니다.

Client

public class Demo {
    private static Application configureApplication() {
        Application app;
        GUIFactory factory;
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.contains("mac")) {
            factory = new MacOSFactory();
        } else {
            factory = new WindowsFactory();
        }
        app = new Application(factory);
        return app;
    }

    public static void main(String[] args) {
        Application app = configureApplication();
        app.paint();
    }
}

Configuration 파일을 적용해 Application에 Concrete Factory의 의존성을 주입해주고 있습니다.

[실행결과]

MacOSButton.paint
MacOSCheckBox.paint

저의 경우 MacOS를 사용하기 때문에 MacOS관련 버튼과 체크박스가 실행된 것을 확인 할 수 있습니다.

언제 적용하면 좋을까요?

  • 코드가 관련 제품의 다양한 제품과 함께 작동해야 하는데, 구체적인 클래스에 의존하지 않으려는 경우
  • 기본 책임을 모호하게 만드는 일련의 팩토리 메서드가 있는 클래스가 있는 경우

장점 및 단점

장점

  • Factory에서 받는 제품이 서로 호환되는지 확인 할 수 있다.
  • 구체적인 제품과 클라이언트 코드 간의 강한 결합을 피할 수 있다.
  • SRP(단일 책임 원칙) : 제품 생성 코드를 한 곳에 추출해 코드를 지원하게 쉽게 만들 수 있다.
  • OCP(개방 폐쇄 원칙) : 기존 클라이언트 코드를 손상시키지 않고, 새로운 변형 제품을 도입할 수 있다.

단점

  • 코드가 다소 복잡해질 수 있다.

예제 코드가 필요하신 분들은 다음에서 확인해 보실 수 있습니다.
추상팩토리 예제코드 바로가기


출처
refactoring guru

'DesignPatterns' 카테고리의 다른 글

팩토리 메서드란? (Factory Method)  (0) 2023.06.15