본문 바로가기

Pattern/GOF

생성패턴 - 팩토리메서드

반응형

1. 팩토리메서드 패턴이란?

Factory method는 부모 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며 자식 클래스가 어떤 객체를 생성할지를 결정하도록 하는 패턴이기도 하다.

 

2. 종류

 

- 단순한 방식

팩토리메소드 패턴 중 가장 간단한 유형으로 생성 클래스를 외부에 두어 타입에 맞는 객체를 생성하여 반환하는 방식이다.

 

CoffeeFacotry(생성 클래스)

public class CoffeeFactory
{
    public static Coffee orderCoffee(String recipe)
    {
        if (recipe.equals("LATTE"))
        {
            return new Latte(recipe, 4000);
        }
        else if (recipe.equals("AMERICANO"))
        {
            return new Americano(recipe, 2000);
        }
        throw new IllegalArgumentException("Undefined parameter");
    }
}

생성 클랙스를 외부에 두고 create 메소드를 static으로 많이 사용한다.

위 코드는 생성 역할을 분리하는데 중점을 두었으나 Coffee 클래스의 기능과 속성이 추가될 수록 생성 클래스의 부담이 커지게 된다.

 

Coffee

public class Coffee
{
    private String recipe;
    private int price = 0;

    public Coffee(String recipe, int price) {
        this.recipe = recipe;
        this.price = price;
    }

    public void orderComplete()
    {
        System.out.println("주문하신 " + recipe + "가 나왔습니다.");
        System.out.println("가격은 : " + price + "입니다.");
    }
}

 

Americano

public class Americano extends Coffee
{
    public Americano(String recipe, int price) {
        super(recipe, price);
    }
}

 

Latte

public class Latte extends Coffee
{
    public Latte(String recipe, int price) {
        super(recipe, price);
    }
}

 

Client

public class Client
{
    public static void main(String[] args) {
        Coffee americano = CoffeeFactory.orderCoffee("AMERICANO");
        americano.orderComplete();

        System.out.println();

        Coffee latte = CoffeeFactory.orderCoffee("LATTE");
        latte.orderComplete();
    }
}

 

결과

 

- 추상화 방식

인터페이스를 사용하여 각 서브 클래스에서 객체를 생성할 수 있게 만드는 방식이다. ExoPlayer 같이 큰 라이브러리에서도 이 방식을 사용하고 있는 만큼 사용성에 대해서 의심할 필요가 없어보인다.

 

CoffeeFactory

public interface CoffeeFactory
{
    default Coffee orderCoffee()
    {
        Coffee coffee = createCoffee();
        return coffee;
    }

    Coffee createCoffee();
}

첫 번째 방식과는 다르게 CoffeeFacotry를 인터페이스로 선언하였다.

createCoffee라는 메소드를 선언하여 상속 받는 서브 클래스에서 구현체를 반환할 수 있도록 하였다.

 

Americano

public class Americano extends Coffee
{

    public Americano() {
        super("AMERICANO", 2000);
    }
}

Americano 클래스 안에서 속성 값들을 초기화 하도록 해주었다.

이렇게 작성하면 생성 시점에 각 클래스마다 고유한 속성이나 기능들을 세팅할 수 있다는 장점이 있다.

 

AmericanoFactory

public class AmericanoFactory implements CoffeeFactory
{
    @Override
    public Coffee createCoffee() {
        return new Americano();
    }
}

AmericanoFactory는 CoffeeFacotry 인터페이스를 상속 받아 createCoffee를 구체화하는 클래스이다.

커피 종류에 따라 만들어지는 생성 클래스이므로 커피 종류와 1:1 관계를 맺는다.

 

 

 

Client

public class Client
{
    public static void main(String[] args) {

        Coffee americano = new AmericanoFactory().orderCoffee();
        americano.orderComplete();

        System.out.println();

        Coffee latte = new LatteFactory().orderCoffee();
        latte.orderComplete();
    }
}

 

결과

 

AmericanoFactory와 같은 생성 클래스는 커피 종류마다 만들어줘야 한다는 단점이 존재한다.

클래스 파일들이 많아지면 관리하기 어려워지기 때문에 ExoPlayer에서는 팩토리 생성 클래스를 이너클래스 방식으로 사용하고 있다.

 

LATTE를 이너 클래스 방식으로 변경해보자.

 

LATTE

public class Latte extends Coffee
{
    public Latte(String recipe, int price) {
        super(recipe, price);
    }

    public static class Factory implements CoffeeFactory
    {
        String recipe;
        int price;

        public Factory() {
            this("LATTE", 4000);
        }

        public Factory(int price) {
            this("LATTE", price);
        }

        private Factory(String recipe, int price) {
            this.recipe = recipe;
            this.price = price;
        }

        @Override
        public Coffee createCoffee() {
            return new Latte(recipe, price);
        }
    }
}

LATTE 클래스 안에 Factory 클래스를 선언하였다.

외부에서 가격을 변경할 수 있도록 price 생성자를 두었고 recipe는 변경되면 안되는 데이터 이기 때문에 세번째 생성자를 private으로 선언해주었다. (외부에서 값을 받아야 하고 속성 값이 많다면 Factory 대신 Builder를 사용하는게 더 좋아보인다)

Client

public class Client
{
    public static void main(String[] args) {

        Coffee americano = new AmericanoFactory().orderCoffee();
        americano.orderComplete();

        System.out.println();

        Coffee latte = new Latte.Factory().orderCoffee();
        latte.orderComplete();
    }
}

 

결과

반응형

'Pattern > GOF' 카테고리의 다른 글

행위패턴 - 책임 연쇄 패턴  (0) 2022.05.31
구조패턴 - 프록시  (0) 2022.05.26
구조패턴 - 데코레이션 패턴  (0) 2022.05.24
구조패턴 - 컴포짓패턴  (0) 2022.05.23
생성패턴- 싱글톤  (0) 2022.05.09