[디자인패턴] 팩토리 패턴, Factory Pattern (Simple Factory, Factory Method, Abstract Factory)

sunny·2023년 3월 5일
0

디자인 패턴

목록 보기
3/11
post-thumbnail

팩토리 패턴, Factory Pattern (Simple Factory, Factory Method, Abstract Factory)


심플 팩토리 패턴 (Simple Factory Pattern)

객체를 생성하는 클래스를 따로 두는 패턴

  • 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화
  • 상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 개게 생성에 관한 구체적인 내용을 결정
  • 👍 상위 클래스와 하위 클래스가 분리되기 때문에 느슨한 결합을 가지며 상위 클래스에서는 인스턴스 생성 방식에 대해 전혀 알 필요가 없기 때문에 더 많은 유연성을 갖게 된다.
  • 👍 객체 생성 로직이 따로 떼어져 있기 때문에 코드를 리팩터링하더라도 한 곳만 고칠 수 있게 되니 유지 보수성이 증가한다.
  • 👎 새로 생성할 객체가 늘어날 때마다, Factory 클래스에 추가해야 되기 때문에 클래스가 많아진다.

43b09446-d183-4a9c-a32b-93048a4062e3 (1)

예제 코드

public class CoffeeFactory {
    public Coffee orderCoffee(String type) {
        Coffee coffee = createCoffee(type);
        coffee.complete();
        return coffee;
    }
    private Coffee createCoffee(String type) {
        return switch (type) {
            case "Latte" -> new Latte();
            case "Americano" -> new Americano();
            default -> null;
        };
    }
}
// 커피 인터페이스
public interface Coffee {
    void complete();
    void drink();
}
// 라떼
public class Latte implements Coffee {
    @Override
    public void complete() {
        System.out.println("라떼 완성");
    }
    
    @Override
    public void drink() {
        System.out.println("라떼 마시기");
    }
}
// 아메리카노
public class Americano implements Coffee {
    @Override
    public void complete() {
        System.out.println("아메리카노 완성");
    }

    @Override
    public void drink() {
        System.out.println("아메리카노 마시기");
    }
}
// 클라이언트가 커피 공장에서 커피를 주문한다.
public class Demo {
    public static void main(String[] args) {
        CoffeeFactory coffeeFactory = new CoffeeFactory();
        Coffee coffee = coffeeFactory.orderCoffee("Latte");
        coffee.drink();
    }
}

팩토리 메소드 패턴 (Factory Method Pattern)

클래스의 인스턴스를 만드는 일을 서브 클래스에게 맡기는 것

  • 인스턴스 생성을 서브 클래스에 위임
  • 부모 추상 클래스는 인터페이스에만 의존하고 실제로 어떤 구현 클래스를 호출할 지는 서브 클래스에서 구현
  • 새로운 구현 클래스가 추가 되어도 기존 Factory 코드의 수정 없이 새로운 Factory를 추가하면 된다.
  • 👍 수정에 닫혀있고 확장에는 열려있는 OCP 원칙을 지킬 수 있다
  • 👎 코드량 증가

Untitled (2)

예제 코드

public interface CoffeeFactory {
    default Coffee orderCoffee() {
        Coffee coffee = createCoffee();
        coffee.complete();
        return coffee;
    }
    Coffee createCoffee();
}
public class LatteFactory implements CoffeeFactory {
    @Override
    public Coffee createCoffee() {
        return new Latte();
    }

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

}
// 커피 인터페이스
public interface Coffee {
    void complete();
    void drink();
}
// 라떼
public class Latte implements Coffee {
    @Override
    public void complete() {
        System.out.println("라떼 완성");
    }
    
    @Override
    public void drink() {
        System.out.println("라떼 마시기");
    }
}
// 아메리카노
public class Americano implements Coffee {
    @Override
    public void complete() {
        System.out.println("아메리카노 완성");
    }

    @Override
    public void drink() {
        System.out.println("아메리카노 마시기");
    }
}
// 클라이언트가 커피 공장에서 커피를 주문한다.
public class Demo {
    public static void main(String[] args) {
        LatteFactory latteFactory = new LatteFactory();
        Coffee coffee1 = latteFactory.orderCoffee();
        coffee1.drink();

        AmericanoFactory americanoFactory = new AmericanoFactory();
        Coffee coffee2 = americanoFactory.orderCoffee();
        coffee2.drink();
    }
}

💡 심플 팩토리에서는 CoffeeFactory가 Latte, Americano 객체를 만들었지만, 팩토리 메소드 패턴에서는 LatteFactory와 AmericanoFactory에서 각각 Latte와 Americano 객체를 만든다.

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

서로 연관되거나 의존적인 객체들의 조합을 만드는 인터페이스를 제공하는 패턴

  • 추상 팩토리 패턴은 연관된 객체들의 생성을 하나의 팩토리에서 담당
  • 👍 수정에는 닫혀있고 확장에는 열려있다
  • 👍 여러 개의 비슷한 집합 객체 생성을 하나의 팩토리에 모아둘 수 있다
  • 👎 클래스 개수 증가

https://user-images.githubusercontent.com/88873302/222947574-063c04d3-d67a-4a59-be85-16fefc4b8a2f.png

👉 아메리카노는 kenya 원두를, 라떼는 normal 원두를 사용한다고 가정하자.

예제 코드

public interface CoffeeFactoryOfFactory {
    CoffeeFactory requestCoffee(String type);
}
public class DefaultCoffeeFactoryOfFactory implements CoffeeFactoryOfFactory {
    @Override
    public CoffeeFactory requestCoffee(String type) {
        switch (type) {
            case "Latte":
                return new LatteFactory();
            case "Americano":
                return new AmericanoFactory();
        }
        throw new IllegalArgumentException();
    }
}

public interface CoffeeFactory {
    Coffee createCoffee();
    Bean createBean();
}
public class LatteFactory implements CoffeeFactory {
    @Override
    public Coffee createCoffee() {
        Bean bean = createBean();
        bean.putBean();
        return new Latte();
    }
    @Override
    public Bean createBean() {
        return new NormalBean();
    }
}
public class AmericanoFactory implements CoffeeFactory {
    @Override
    public Coffee createCoffee() {
        Bean bean = createBean();
        bean.putBean();
        return new Americano();
    }
    @Override
    public Bean createBean() {
        return new KenyaBean();
    }
}

public interface Bean {
    void putBean();
}
public class NormalBean implements Bean {
    @Override
    public void putBean() {
        System.out.println("일반 원두");
    }
}
public class KenyaBean implements Bean {
    @Override
    public void putBean() {
        System.out.println("케냐 원두");
    }
}

public interface Coffee {
    void complete();
    void drink();
}
public class Latte implements Coffee {
    @Override
    public void complete() {
        System.out.println("라떼 완성");
    }

    @Override
    public void drink() {
        System.out.println("라떼 마시기");
    }
}
public class Americano implements Coffee {
    @Override
    public void complete() {
        System.out.println("아메리카노 완성");
    }

    @Override
    public void drink() {
        System.out.println("아메리카노 마시기");
    }
}

public class Demo {
    public static void main(String[] args) {
        CoffeeFactoryOfFactory coffeeFactoryOfFactory = new DefaultCoffeeFactoryOfFactory();
        CoffeeFactory latteFactory = coffeeFactoryOfFactory.requestCoffee("Latte");
        Coffee latte = latteFactory.createCoffee();
        latte.complete();
        latte.drink();

        CoffeeFactory americanoFactory = coffeeFactoryOfFactory.requestCoffee("Americano");
        Coffee americano = americanoFactory.createCoffee();
        americano.complete();
        americano.drink();
    }
}

💡 CoffeeFactory 에서 CoffeeBean 을 생성할 수 있다. LatteFactoryLatteNormalBean 조합으로 객체를 생성할 수 있고, AmericanoFactoryAmericanoKenyaBean 의 조합으로 객체를 생성할 수 있다.

💡 즉, CoffeeFactoryCoffeeBean 을 조합하는 구현체를 제공한다.


참고 자료

0개의 댓글