본문 바로가기
디자인패턴

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

by 이석준석이 2021. 5. 22.

사용 의도

  • 서로 관련성이 있거나, 독립적인 여러 객체를 생성하기 위한 인터페이스를 제공합니다.
  • 아래의 설명에서는 서로 관련성이 있는 경우에 객체를 생성하는 인터페이스를 제공하는 예시를 통해 추상팩토리 패턴을 설명해보겠습니다.

예시) 화이트모드와 다크모드 개발

  • 기획자에게 화이트모드와 다크모드의 경우에 달라지는 화면을 만들어달라는 요구를 받았습니다.
화이트모드 다크모드
배경화면의 색상이 흰색이어야 한다. 배경화면의 색상이 검은색이어야 한다.
제공되는 폰트는 BOLD 여야 하며, 크기는 10이어야한다. 제공되는 폰트는 ITALIC 이어야 하며, 크기는 12여야한다.

이를 위해 개발자 A는 아래와 같이 클래스를 구성한 뒤, 화면클래스를 반환하도록 하였습니다.

  • 화면 클래스 (Window)
  • 폰트 클래스 (Font)
  • 배경화면 클래스 (Background)
public class Window {
    private Font font;
    private Color color;

    public void setFont(Font font) {
        this.font = font;
    }

    public void setColor(Color color) {
        this.color = color;
    }
}

 

생성 측에서, 아래와같은 코드가 되겠네요

public class WindowCreator {
    public Window createWindow(Mode mode) {
        Window window = new Window();

        switch (mode) {
            case DARK:
                Font font = new Font();
                font.setSize(10);
                font.setType(Type.BOLD);
                window.setFont(font);

                Background background = new Background();
                background.setColor(Color.WHITE);
                window.setBackground(background);
            case WHITE:
                Font font2 = new Font();
                font2.setSize(12);
                font2.setType(Type.ITALIC);
                window.setFont(font2);

                Background background2 = new Background();
                background2.setColor(Color.BLACK);
                window.setBackground(background2);
        }
        
        return window;
    }
}

 

 

개발을 마친뒤에, API 스펙을 해당 개발자는 공개했고 성황리에 사용됐습니다.

 

  • 하지만 업데이트를 통해 기획서가 변경되었습니다.
화이트모드 다크모드
배경화면의 색상이 흰색이어야 한다. 배경화면의 색상이 검은색->회색이어야 한다.
제공되는 폰트는 BOLD->ITALIC 여야 하며, 크기는 10이어야한다. 제공되는 폰트는 ITALIC->BOLD 이어야 하며, 크기는 12여야한다.

이러한 경우에 클라이언트측의 코드는 아래와 같이 변경될것입니다.

  • 이러한 경우의 단점은 2가지로 볼 수 있습니다.
    1. Creator 쪽의 코드가 복잡해진다.
      • 모드가 출시될 때마다, 코드가 증가하는 단점
    2. 다크모드 / 화이트모드가 변경되는 경우, Creator 측의 코드가 수정되어야한다.
      • 변경에 유연하지 못하게됩니다.
public class WindowCreator {
    public Window createWindow(Mode mode) {
        Window window = new Window();

        switch (mode) {
            case DARK:
                Font font = new Font();
                font.setSize(10);
                font.setType(Type.ITALIC); // changed
                window.setFont(font);

                ...
            case WHITE:
                Font font2 = new Font();
                font2.setSize(12);
                font2.setType(Type.BOLD); // changed
                window.setFont(font2);

                Background background2 = new Background();
                background2.setColor(Color.GRAY); // changed
                window.setBackground(background2);
        }

        return window;
    }
}

 

모드가 변경되었는데 Creator 측의 코드를 변경해야하는 일이 일어났고, 개발자 A는 화가나버렸습니다.

또한 모드가 만약 많고, 기획서가 대규모로 변경되면 더 많이 변경해야 한다는 생각이 들어버린 개발자 A는 퇴사를해버렸습니다.


개발자 B는 추상팩토리를 이용하여 아래와 같이 클래스구조를 구성하였습니다.

 

 

배경화면

public abstract class Background {
    public abstract Color getColor();
}
public class BlackBackground extends Background {
    @Override
    public Color getColor() {
        return Color.BLACK;
    }
}
public class WhiteBackground extends Background {
    @Override
    public Color getColor() {
        return Color.WHITE;
    }
}

 

폰트

public abstract class Font {
    public abstract int getSize();
    public abstract Type getType();
}
public class BlackFont extends Font {
    @Override
    public int getSize() {
        return 10;
    }

    @Override
    public Type getType() {
        return Type.BOLD;
    }
}
public class WhiteFont extends Font {
    @Override
    public int getSize() {
        return 12;
    }

    @Override
    public Type getType() {
        return Type.ITALIC;
    }
}

 

팩토리

public abstract class WindowFactory {
    public abstract Background createBackground();
    public abstract Font createFont();
}
public class BlackWindowFactory extends WindowFactory {
    @Override
    public Background createBackground() {
        return new BlackBackground();
    }

    @Override
    public Font createFont() {
        return new BlackFont();
    }
}
public class WhiteWindowFactory extends WindowFactory {
    @Override
    public Background createBackground() {
        return new WhiteBackground();
    }

    @Override
    public Font createFont() {
        return new WhiteFont();
    }
}

 

생성

public class WindowCreator {
    public Window createWindow(WindowFactory windowFactory) {
        final Window window = new Window();
        final Background background = windowFactory.createBackground();
        final Font font = windowFactory.createFont();

        window.setBackground(background);
        window.setFont(font);

        return window;
    }
}

 

위의 경우에는, 기획안이 변경됨에 따라서 Creator 부분은 전혀 변경되지 않습니다.

  • 화이트모드의 폰트의 크기가 변경되면 BlackFont 클래스를 변경하면되며
  • 다크모드의 배경화면 색상이 변경되면 WhiteBackground 클래스를 변경하면됩니다.
  • 또한 새로운 모드(옐로우 모드) 가 추가될 시에도 Creator 부분은 변경이 되지 않습니다.

장점은 아래와 같습니다.

 

※ 클래스의 생성과 구현클래스의 책임이 분리됩니다.

※ Creator에는 font 사이즈가 몇인지, 타입은 무엇인지 등에 대한 정보가 노출되지 않습니다. (캡슐화)

※ 변경에 유연합니다.