개발/디자인패턴

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

nova_dev 2022. 3. 3. 23:59
반응형

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

추상 팩토리 패턴은 팩토리 메서드 패턴을 확장한 패턴이다.

 

 추상 팩토리 패턴이란?

  • 추상 팩토리 패턴은 팩토리 메서드 패턴을 확장한 패턴이다.
  • 이 말은 즉슨, 팩토리 메서드를 여러 개를 만들고 그룹핑해서 하나로 관리할 수 있도록 만든 게 추상 팩토리 패턴이라고 볼 수 있다.

 팩토리 패턴 vs 팩토리 메서드 패턴 vs 추상 팩토리 패턴

  • 팩토리 패턴 vs 팩토리 메서드 패턴
    추상화의 여부로 알 수 있다. 팩토리는 바로 클래스들의 생성을 한 곳에 모아서 new로 관리해주고, 팩토리 메서드는 추상화한 상위 클래스 아래에 하위 클래스를 두고, 실제 객체의 생성은 하위 클래스에게 위임한다. (선언과 구현을 분리한다.)
  • 팩토리 메서드 패턴 vs 추상 팩토리 패턴
    추상화된 그룹을 형성하고 관리한다는 점에서 차이가 있다. 추상 팩토리는 추상화한 팩토리들을 그룹 지어 관리한다. 즉, 추상 팩토리는 여러 개의 팩토리 메서드를 그룹으로 묶어 놓은 것과 같다. 추상 팩토리는 다양한 객체 생성 과정에서 그룹화가 필요할 경우 유용하다.
  • 팩토리 패턴) https://hirlawldo.tistory.com/158
  • 팩토리 메서드 패턴) https://hirlawldo.tistory.com/163

 

 

[Java][디자인 패턴] 1. 팩토리 패턴

디자인패턴 [Java][디자인 패턴] 1. 팩토리 패턴 객체 생성 과정을 담당할 별도의 클래스를 선언하여 생성되는 객체의 구조를 느슨한 관계로 변경할 수 있다.  팩토리 패턴이란? 팩토리 패턴은 객

hirlawldo.tistory.com

 

[Java][디자인 패턴] 3. 팩토리 메서드 패턴

디자인 패턴 [Java][디자인 패턴] 3. 팩토리 메서드 패턴 팩토리 메서드 패턴은 팩토리 패턴의 확장 패턴으로, 팩토리 패턴과 템플릿 메서드 패턴이 결합된 패턴이다.  팩토리 메서드 패턴이란

hirlawldo.tistory.com

 추상 팩토리 패턴 구조

예시 코드는 쉽게 배워 바로 써먹는 디자인 패턴에서 나온 PHP 예시 코드를 Java 코드로 바꾸고 약간 변형한 코드이다.
(좋은 예시가 떠오르지 않아서 책에 있는 예시를 참고했다.)

CarFactory 추상 팩토리

추상 팩토리 패턴은 위와 같이 해결해야 하는 목적에 따라 그룹을 만든다. 예를 들어 위와 같이 하나의 차를 만들기 위한 목적을 달성하기 위해 Car를 구성하는 Tire, Door, Engine 등의 그룹이 있다고 가정해보자. 그럴 때 각각의 그룹을 달성하는 방법도 여러 가지가 있을 수 있다. 예를 들면 현대차가 해외에 팔렸을 때에는 Door, Tire가 동작하는 방식이 다를 수 있고, 각 공장별로 다른 전체적인 구성은 같더라도 다른 동작을 수행할 수 있다. 혹은 2차 벤더, 3차 벤더가 각각 다른 곳이 수주할 수도 있다. 이럴 경우 Tire와 Door 등의 각각의 그룹에 대한 목적을 달성하고, 그 추상 그룹들을 이용해 완성된 차를 만드는 CarFactory가 TireProduct, DoorProduct 추상 클래스를 이용하여 완성품 차를 만들 수 있다.

팩토리 패턴 코드

1. DoorProduct, TireProduct 추상 클래스

public abstract class DoorProduct {
    public abstract String makeAssemble();
}
public abstract class TireProduct {
    public abstract String makeAssemble();
}

2.DoorProduct, TireProduct를 실제로 구현하는 클래스들
- 미국산, 한국산 Door와 Tire를 실제로 만드는 팩토리 클래스들
- 이전에 팩토리 메서드에서 하나의 추상 팩토리가 있고, 그 아래 하위 클래스들이 있는데 DoorProduct 하나가 팩토리 메서드라고 보면 된다.

public class KoreaDoorProduct extends DoorProduct {
    @Override
    public String makeAssemble() {
        return "문이 열립니다.";
    }
}
public class KoreaTireProduct extends TireProduct {
    public KoreaTireProduct() {
    }

    @Override
    public String makeAssemble() {
        return "국산 타이어";
    }
}
public class StateDoorProduct extends DoorProduct {

    @Override
    public String makeAssemble() {
        return "Door is open";
    }
}
public class StateTireProduct extends TireProduct {
    public StateTireProduct() {
    }

    @Override
    public String makeAssemble() {
        return "미국산 타이어";
    }
}

3. CarFactory로 Korea, State 차를 조립해서 생성하는 CarFactory 추상 클래스

public abstract class CarFactory {
    public abstract TireProduct createTire();
    public abstract DoorProduct createDoor();
}
public class KoreaCarFactory extends CarFactory{
    public KoreaCarFactory() {

    }

    @Override
    public TireProduct createTire() {
        return new KoreaTireProduct();
    }

    @Override
    public DoorProduct createDoor() {
        return new KoreaDoorProduct();
    }
}
public class StateCarFactory extends CarFactory {
    @Override
    public TireProduct createTire() {
        return new StateTireProduct();
    }

    @Override
    public DoorProduct createDoor() {
        return new StateDoorProduct();
    }
}

4. CarFactory로 차가 잘 만들어지나 확인하는 테스트 코드

class CarFactoryTest {

    @Test
    @DisplayName("한국산 차 만들기")
    void makeKoreaCar(){
        // given
        CarFactory carFactory = new KoreaCarFactory();
        TireProduct tireProduct = carFactory.createTire();
        DoorProduct doorProduct = carFactory.createDoor();

        // when
        String tire = tireProduct.makeAssemble();
        String door = doorProduct.makeAssemble();

        // then
        assertEquals("국산 타이어", tire);
        assertEquals("문이 열립니다.", door);
    }


    @Test
    @DisplayName("미국산 차 만들기")
    void makeStateCar(){
        // given
        CarFactory carFactory = new StateCarFactory();
        TireProduct tireProduct = carFactory.createTire();
        DoorProduct doorProduct = carFactory.createDoor();

        // when
        String tire = tireProduct.makeAssemble();
        String door = doorProduct.makeAssemble();

        // then
        assertEquals("미국산 타이어", tire);
        assertEquals("Door is open", door);
    }
}

 

 만약 추상 팩토리에 새로운 부품을 추가한다면?

만약 추상 팩토리에 새로운 부품인 Engine을 추가해야 한다면 어떻게 될까?
이 경우, 추상 클래스 그룹으로 분리된 모든 클래스에 Engine 부품 관련 코드를 삽입해야 한다. 이와 같이 추상 팩토리 패턴은 그룹을 나누는 것은 쉽지만 서브 생성 객체를 추가하는 것은 어렵다. 즉 생성된 그룹을 통해 전체를 쉽게 변경하거나 관리하기 쉽다는 장점은 있지만 서브 생성 객체를 추가해야 한다면 OCP를 위반하게 되기 때문에 확장성 부분에서는 좋지 않을 수 있다는 점에 주의해야 한다.

 Github 코드

Github 예제 코드 링크

Github 예제 테스트 코드 링크

참고 자료

 

 

 

 

 

반응형