개발/디자인패턴

[Java][디자인 패턴] 1. 팩토리 패턴 (Factory Pattern)

nova_dev 2022. 2. 28. 23:59
반응형

디자인패턴
[Java][디자인 패턴] 1. 팩토리 패턴 (Factory Pattern)

객체 생성 과정을 담당할 별도의 클래스를 선언하여 생성되는 객체의 구조를 느슨한 관계로 변경할 수 있다.

 

 팩토리 패턴이란?

  • 팩토리 패턴은 객체 생성 과정을 분리하여 처리한다.
  • 객체 생성 과정에서 발생하는 new 키워드의 문제점을 해결하고 느슨한 객체 생성을 관리할 수 있다.
  • 팩토리 패턴과 프록시 패턴을 결합하면 객체 생성을 위임받을 때 권한에 따라 접근하는 것을 제어할 수 있다.
  • 단순 팩토리 패턴은 메서드를 통해 객체 생성을 관리할 수 있다.

 팩토리 패턴 구조

Coffee Factory 예제 코드

예제 코드로 작성한 Coffee를 Americano, CafeLatte, VanillaLatte와 같은 종류별로 생성하는 CoffeeFactory라는 예제 코드의 구조이다. CoffeeFactory는 Coffee 인터페이스를 구현하고 있는 각 커피들을 생성해주는 공장과 같은 역할을 한다.

CoffeeFactory의 getInstance 메서드는 커피의 타입 값을 받아서 해당하는 타입의 클래스로 생성하여 반환한다.

팩토리 패턴은 객체의 생성 과정과 

팩토리 패턴 코드

1. Coffee 인터페이스

public interface Coffee {
    String getName();
}

2. Coffee 인터페이스를 구현하고 있는 클래스 (Americano, CafeLatte, VanillaLatte)

public class Americano implements Coffee{

    @Override
    public String getName() {
        return CoffeeType.AMERICANO.getDisplayName();
    }
}
public class CafeLatte implements Coffee{
    @Override
    public String getName() {
        return CoffeeType.CAFE_LATTE.getDisplayName();
    }
}
public class VanillaLatte implements Coffee{
    @Override
    public String getName() {
        return CoffeeType.VANILLA_LATTE.getDisplayName();
    }
}

3. 커피 타입으로 타입에 맞는 Coffee 클래스를 생성해주는 CoffeeFactory 클래스

public class CoffeeFactory {

    public static Coffee getInstance(CoffeeType randomTodayPick) {
        switch (randomTodayPick) {
            case AMERICANO:
                return new Americano();

            case CAFE_LATTE:
                return new CafeLatte();

            case VANILLA_LATTE:
                return new VanillaLatte();

        }
        throw new IllegalArgumentException("잘못된 커피 요청입니다.");
    }
}

4. CoffeeFactory 클래스를 이용하여 커피 객체를 가져오는 Customer 클래스
CoffeeFactory 클래스를 사용하여 직접적으로 커피 클래스를 new 하여 생성해서 사용하는 것이 아니라 CoffeeFactory.getInstance(coffeeType) 메서드를 통해 생성된 커피 객체를 가져올 수 있다.

public class Customer {
    public String drinkCoffee(CoffeeType type){
        Coffee coffee = CoffeeFactory.getInstance(type);
        return coffee.getName();
    }
}

5. Coffee 인터페이스를 상속한 클래스들의 타입들을 지정해주는 CoffeeType enum 

public enum CoffeeType {
    AMERICANO("AMERICANO", "아메리카노"),
    CAFE_LATTE("CAFE_LATTE", "카페 라떼"),
    VANILLA_LATTE("VANILLA_LATTE", "바닐라 라떼"),
    ;
    private final String code;
    private final String displayName;

    CoffeeType(String code, String displayName) {
        this.code = code;
        this.displayName = displayName;
    }

    public String getCode() {
        return code;
    }

    public String getDisplayName() {
        return displayName;
    }
}

6. 각 커피 타입들에 해당하는 커피가 제대로 나왔는지 확인하는 Test Code

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class CustomerTest {

    @DisplayName("아메리카노를 마신다")
    @Test
    void drinkCoffeeAmericano() {
        // given
        Customer customer = new Customer();

        // when
        String coffeeName = customer.drinkCoffee(CoffeeType.AMERICANO);
        System.out.println("오늘은 너로 정했다! " + coffeeName);

        // then
        Assertions.assertEquals(CoffeeType.AMERICANO.getDisplayName(), coffeeName);
    }

    @DisplayName("카페라떼를 마신다")
    @Test
    void drinkCoffeeCafeLatte() {
        // given
        Customer customer = new Customer();

        // when
        String coffeeName = customer.drinkCoffee(CoffeeType.CAFE_LATTE);
        System.out.println("오늘은 너로 정했다! " + coffeeName);

        // then
        Assertions.assertEquals(CoffeeType.CAFE_LATTE.getDisplayName(), coffeeName);
    }

    @DisplayName("바닐라라떼를 마신다")
    @Test
    void drinkCoffeeVanilla() {
        // given
        Customer customer = new Customer();

        // when
        String coffeeName = customer.drinkCoffee(CoffeeType.VANILLA_LATTE);
        System.out.println("오늘은 너로 정했다! " + coffeeName);

        // then
        Assertions.assertEquals(CoffeeType.VANILLA_LATTE.getDisplayName(), coffeeName);
    }


}

 팩토리 패턴의 장점과 단점

장점

  • 코드에서 생성과 관련된 모든 처리를 별도의 클래스 객체로 위임할 수 있다.
  • 유연성과 확장성이 개선된다
  • 팩토리 패턴은 어떤 객체를 생성할지 모르는 초기 단계 코드에서 매우 유용하다.

단점

  • 팩토리 패턴은 객체 생성을 위임하는 데 별도의 새로운 클래스가 필요하다.
  • 관리한 클래스 파일이 늘어난다

 Github 코드

Github 예제 코드 링크

Github 예제 테스트 코드 링크

참고 자료

 

 

 

 

 

반응형