개발 지식 기록/북스터디

[디자인 패턴] 팩토리 패턴

엉망진창좌충우돌 2024. 1. 26. 05:33

 

팩토리 패턴에 대해 자세한 내용에 들어가기에 앞서 GoF의 디자인 패턴 분류를 통해 팩토리 패턴이 어떤 카테고리에 속하는지 미리 확인하고자 한다.

 

출처 :   디자인 패턴 정리 - GOF(Gang of Four) 디자인 패턴들 » Jay's Blog (realzero0.github.io)

 

GoF의 디자인 패턴을 목적에 따라 분류하면 생성 패턴, 구조 패턴, 행위 패턴으로 구분되는데 다음과 같이 정의된다.

(주로 클래스에 적용되는지, 객체에 적용되는지 범위에 따라 구분하기도 한다.)

  • 생성 패턴 - 객체 생성과 관련된 패턴
  • 구조 패턴 - 클래스나 객체들을 조합해 더 큰 구조로 만들 수 있는 패턴
  • 행위 패턴 - 클래스나 객체들이 상호작용하는 방법을 정의한 패턴

 

이번에 살펴볼 팩토리 패턴은 생성 패턴 중 추상 팩토리(Abstract Factory) 패턴과 팩토리 메서드(Factory Method) 패턴이다.

 

팩토리 패턴의 목표는 객체 생성 역할을 별도의 클래스(Factory)에 위임하는 것이다.

팩토리 패턴의 관련된 패턴은 방금 이야기 했던 것처럼 추상 팩토리 패턴과 팩토리 메서드 패턴이 있지만 이 두 가지 패턴의 베이스가 되는 간단한 팩토리(Simple Factory)가 존재한다. 

 

간단한 팩토리부터  팩토리 메서드 패턴, 추상 팩토리 패턴의 순서로 살펴보려 한다.

 

1. 간단한 팩토리 (Simple Factory)

 

생성자의 호출(new)을 별도의 클래스(Factory)에서 담당하고 클라이언트 코드에서는 팩토리를 통해 객체를 생성한다.

(호출하는 부분이 객체의 생성자에 직접 의존하고 있으면 변경 시 수정되어야 하는 코드가 많이 발생하기 때문)

 

예시

public interface Coffee {
}

public class Latte implements Coffee {
}

public class Espresso implements Coffee {
}

 

Coffee 인터페이스를 정의하고 이를 구현하는 Latte와 Espresso 클래스를 만들었다.

 

클라이언트 코드에서 Latte와 Espresso를 다음처럼 생성할 수 있다.

Coffee latte = new Latte();
Coffee espresso = new Espresso();

 

이렇게 생성할 수 있지만 이럴 경우 클라이언트와 Latte, Espresso 사이에 직접적인 의존관계가 생성된다.

이럴 경우 생성자나 코드의 변경이 있을 때 모든 클라이언트 코드의 변경이 발생할 수 있다.

따라서 객체의 생성을 담당하는 별도의 Factory 클래스를 만들어서 생성 역할을 넘긴다.

 

public interface Coffee {
    enum Type {
        LATTE, ESPRESSO
    }
}

 

public class CoffeeFactory {

    public Coffee createCoffee(Coffee.Type coffeeType) {
        switch (coffeeType) {
            case LATTE:
                return new Latte();
            case ESPRESSO:
                return new Espresso();
            default:
                throw new IllegalArgumentException("해당 커피가 없습니다.");
        }
    }
}

 

CoffeeFactory coffeeFactory = new CoffeeFactory();
Coffee Latte = coffeeFactory.createCoffee(Coffee.Type.LATTE);
Coffee Espresso = coffeeFactory.createCoffee(Coffee.Type.ESPRESSO);

 

이렇게 CoffeFactory를 만든 후 Type 에 따라 객체를 생성해서 반환하게 한다.

클라이언트 코드에서 CoffeFactory를 선언 후 생성 메서드를 호출하는 방식이다.

이렇게 작성할 경우 CoffeeFactory와 의존 관계가 생기고 Latte, Espresso와는 직접적인 의존관계가 생기지 않는다.

직접적으로 의존하지 않기 때문에 변경사항이 생길 경우도 CoffeeFactory 내부만 수정하면 된다.

 

다만 새로운 커피가 생길 경우 switch문에 추가되어야 하는데 기존의 코드를 변경하지 않으면서, 기능을 추가할 수 있도록 설계되어야 한다는 개방 폐쇄의 원칙(OCP)에 위반된다는 단점이 있다. 

 

2. 팩토리 메서드 (Factory Method) 패턴

 

팩토리 메서드 패턴은 객체를 생성할 때 어떤 클래스의 인스턴트를 만들지 서브 클래스에서 결정하게 한다.

부모 추상 클래스는 인터페이스에만 의존하고 실제로 어떤 구현 클래스를 호출할 지는 서브 클래스에서 구현한다.

 

예시

 

public interface Coffee {
	void call();
}

 

public class LatteCoffee implements Coffee {
    @Override
    public void call() {
        System.out.println("라떼 커피 나왔어요");
    }
}

 

public abstract class CoffeeFactory {

    public User newInstance() {
        Coffee coffee = createCoffee();
        coffee.call();
        return coffee;
    }

    protected abstract Coffee createCoffee();
}

 

public class LatteCoffeeFactory extends CoffeeFactory {
    @Override
    protected Coffee createCoffee() {
        return new LatteCoffee();
    }
}

 

순서대로 설명하면

Coffee 인터페이스를 정의하고 이를 구현하는 LatteCoffee 클래스를 구현했다.

추상 클래스로 CoffeeFactory를 정의하고, 외부에서 Coffee객체를 생성 시 newInstance를 호출하고, 어떤 객체를 생성할지는 추상 메서드로 정의해서 하위 클래스에서 정의한다.

 

클라이언트에서는 다음처럼 사용할 수 있다.

CoffeeFactory latteCoffeeFactory = new LatteCoffeeFactory();
Coffee latteCoffee = latteCoffeeFactory.newInstance();

 

커피가 추가될 경우 기존 클래스의 변경 없이 새로운 커피 클래스와 새로운 커피 팩토리를 추가하면 된다.

 

팩토리 메서드 패턴의 장점은 수정에 닫혀있고 확장에 열려있는 OCP 원칙을 지킬 수 있다는 것이다.

하지만 많은 클래스를 정의해야 하기 때문에 코드량이 증가한다.

 

3. 추상 팩토리 (Abstract Factory) 패턴

 

추상 팩토리 패턴은 구체적인 클래스에 의존하지 않고 서로 연관되거나 의존적인 객체들의 조합을 만드는 인터페이스를 제공하는 패턴이다.

 

출처 : 위키백과

추상 팩토리 패턴은 이미지에서도 확인할 수 있듯이 연관된 객체들의 생성을 하나의 팩토리에서 담당하는 것이다.

 

예시

 

public interface Samsung {
}

public class SamsungLaptop implements Samsung {
}

public class SamsungTv implements Samsung {
}

 

public interface Lg {
}

public class LgLaptop implements Lg {
}

public class LgTv implements Lg {
}

 

public interface Electronics {
    Samsung createSamsung();
    Lg createLg();
}

public class LaptopFactory implements Electronics {

    @Override
    public SamsungLaptop createSamsung() {
        return new SamsungLaptop();
    }

    @Override
    public LgLaptop createLg() {
        return new LgLaptop();
    }
}

public class TvFactory implements Electronics {

    @Override
    public SamsungTv createSamsung() {
        return new SamsungTv();
    }

    @Override
    public LgTv createLg() {
        return new LgTv();
    }
}

 

클라이언트에서 다음처럼 작동한다.

public class AbstractFactoryApp {
    public static void main(String[] args) {
        use(new LaptopFactory());
        use(new TvFactory());
    }

    private static void use(Electronics factory) {
        Samsung samsung = factory.createSamsung();
        Lg lg = factory.createLg();
    }
}

 

추상 팩토리의 장점으로는 여러 개의 비슷한 집합 객체 생성을 하나의 팩토리에 모아둘 수 있다는 것이다.

다만 팩토리 메서드와 마찬가지로 객체가 늘어날 때 마다 클래스가 증가하여 코드의 복잡성이 증가한다.(팩토리 패턴의 공통적인 문제다.) 또한 추상 팩토리의 세부 사항이 변경되면 모든 팩토리를 수정해야 한다.

 

추상 팩토리와 팩토리 메서드의 비교

 

  팩토리 메서드 패턴 추상 팩토리 패턴
공통점 객체 생성 과정을 추상화한 인터페이스를 제공
차이점 구체적인 객체 생성과정을 하위 또는 구체적인 클래스로 옮기는 것이 목적 관련 있는 여러 객체를 구체적인 클래스에 의존하지 않고 만들 수 있게 해주는 것이 목적
한 Factory 당 한 종류의 객체 생성 지원 한 Factory에서 서로 연관된 여러 종류의 객체 생성을 지원(제품'군' 생성 지원)

 

 

출처 :

Factory 패턴 (3/3) - Abstract Factory (추상 팩토리) 패턴 :: 뱀귤 블로그 (tistory.com)

 

Factory 패턴 (3/3) - Abstract Factory (추상 팩토리) 패턴

1. Overview Factory 패턴 시리즈의 마지막인 추상 팩토리 패턴입니다. 추상 팩토리는 얼핏 보면 팩토리 메서드 패턴과 비슷하다고 느낄 수도 있습니다. 가장 큰 차이점은 팩토리 메서드 패턴은 어떤

bcp0109.tistory.com

Factory 패턴 (2/3) - Factory Method (팩토리 메서드) 패턴 :: 뱀귤 블로그 (tistory.com)

 

Factory 패턴 (2/3) - Factory Method (팩토리 메서드) 패턴

1. Overview Factory 패턴은 객체 생성과 관련된 디자인 패턴입니다. 1편에서 봤던 Simple Factory 는 객체 생성 역할을 담당하면서 각 클라이언트에서 구현 클래스에 직접 의존하지 않도록 분리했습니다.

bcp0109.tistory.com

Factory 패턴 (1/3) - Simple Factory :: 뱀귤 블로그 (tistory.com)

 

Factory 패턴 (1/3) - Simple Factory

1. Overview Factory 패턴은 객체 생성 역할을 별도의 클래스 (Factory) 에게 위임하는 것이 가장 궁극적인 목표입니다. 디자인 패턴 중 Facotry 와 관련된 패턴은 크게 두 가지가 있습니다. 팩토리 메서드

bcp0109.tistory.com

💠 추상 팩토리(Abstract Factory) 패턴 - 완벽 마스터하기 (tistory.com)

 

💠 추상 팩토리(Abstract Factory) 패턴 - 완벽 마스터하기

Abstract Factory Pattern 추상 팩토리 패턴은 연관성이 있는 객체 군이 여러개 있을 경우 이들을 묶어 추상화하고, 어떤 구체적인 상황이 주어지면 팩토리 객체에서 집합으로 묶은 객체 군을 구현화

inpa.tistory.com