본문 바로가기
Design Pattern/생성 패턴(Creational patterns)

Factory Method Pattern, 팩토리 메서드 패턴

by codeyaki 2023. 6. 7.
반응형

팩토리 메서드 패턴이란?

  • 팩토리 메서드 패턴은 부모(상위)클래스에 알려지지 않은 추상 클래스를 생성하는 패턴으로 자식(하위)클래스가 직접 어떤 객체를 생성할지 결정하도록 하는 패턴!
  • 즉, 객체 생성을 위한 패턴으로 생성과 사용의 분리를 통해서 유연하게 객체를 생성할 수 있게 된다.
  • 또한 객체 생성에 필요한 과정들을 템플릿처럼 정해놓고 각 과정을 구현할 수 있다.

왜 사용하나요?

  • 생성자 (Creator)와 구현 객체(concrete product)의 강한 결합을 피함
  • 객체가 생성될때 반복적으로 할 일을 수행시킬 수 있음
  • 캡슐화, 추상화를 통해 생성되는 객체의 구체적인 타입 은닉
  • 단일 책임 원칙 (SRP) 준수
    • 객체 생성 코드를 한 곳 (패키지, 클래스 등)으로 이동시켜 코드를 유지보수하기 쉽게할 수 있으므로 원칙을 만족
  • 개방 폐쇄 원칙 (OCP) 준수
    • 기존 코드를 수정하지 않고 새로운 유형의 제품 인스턴스를 프로그램에 도입할 수 있음 (확정성 증가)
  • 생성에 대한 인터페이스 부분과 생성에 대한 구현 부분을 따로 나뉘었기 때문에 패키지 분리하여 개별로 여러 개발자가 협업을 통해 개발가능

언제 사용하나요?

  • 클래스의 생성과 사용 로직 분리로 결합도를 낮춰야 할때
  • 캡슐화를 통해 정보 은닉이 필요한 경우
  • 사용자가 구성요소를 확장할 수 있도록 제공해야 할때(라이브러리, 프레임워크 만들때 유용)
  • 기존 객체를 재구성하는 대신 기존 객체를 재사용하여 리소스 절약하고자 할 때

문제점

  • 각 제품 구현체마다 팩토리 객체들을 생성해야하기 때문에, 구현체가 늘어날때 마다 팩토리 클래스가 증가 (서브 클래스 증가)
  • 코드 복잡성 증가

구현 방법 (자바)

 

GitHub - 5onchangwoo/design-pattern: 디자인 패턴을 학습하기 위한 레파지토리

디자인 패턴을 학습하기 위한 레파지토리. Contribute to 5onchangwoo/design-pattern development by creating an account on GitHub.

github.com

1. Pizza 인터페이스 만들기

package com.example.dessignpattern.creational.factorymethod;

public interface Pizza {
    void eat();
}

2. PizaaCreator (피자 생성기) 만들기 

package com.example.dessignpattern.creational.factorymethod;

public abstract class PizzaCreator {
    int count;
    abstract Pizza createPizza();

    public PizzaCreator(int count){
        this.count = count;
    }
}

3. 불고기 피자 & 생성기 만들기

package com.example.dessignpattern.creational.factorymethod;

public class BulgogiPizza implements Pizza{
    @Override
    public void eat() {
        System.out.println("불고기 피자 냠냠 ~");
    }
}
package com.example.dessignpattern.creational.factorymethod;

public class BulgogiPizzaCreator extends PizzaCreator {
    public BulgogiPizzaCreator(int count) {
        super(count);
    }

    @Override
    Pizza createPizza() {
        if(count > 0){
            count--;
            return new BulgogiPizza();
        }
        return new NullPizza();
    }
}

4. 추가로 콤비네이션 피자 메뉴를 만들게 된다면 피자와 생성기만 추가로 만들면됨. (기존의 코드를 건들지 않아 유연한 개발 가능)

package com.example.dessignpattern.creational.factorymethod;

public class CombinationPizza implements Pizza{
    @Override
    public void eat() {
        System.out.println("콤비네이션 피자 냠냠");
    }
}
package com.example.dessignpattern.creational.factorymethod;

public class CombinationPizzaCreator extends PizzaCreator {
    public CombinationPizzaCreator(int count) {
        super(count);
    }

    @Override
    Pizza createPizza() {
        if(count > 0) {
            count--;
            return new CombinationPizza();
        }
        return new NullPizza();
    }
}

 

5. 사용하는 클라이언트

  • 사용하는 클라이언트는 어떤 피자 종류인지 알필요가 없음 (인터페이스인 Pizza 타입으로 받으면 됨)
  • 만약 추가로 더 메뉴가 필요하다면 creator와 해당 메뉴만 추가로 생성하면 끝
package com.example.dessignpattern.creational.factorymethod;

public class Main {
    public static void main(String[] args) {
        // 불고기 피자 생성
        PizzaCreator factory1 = new BulgogiPizzaCreator(2);
        Pizza bulgogiPizza1 = factory1.createPizza();
        bulgogiPizza1.eat();
        Pizza bulgogiPizza2 = factory1.createPizza();
        bulgogiPizza2.eat();
            // 세개는 피자가 없어서 못먹음 ㅜ
        Pizza bulgogiPizza3 = factory1.createPizza();
        bulgogiPizza3.eat();

        // 콤비네이션 피자 생성
        PizzaCreator factory2 = new CombinationPizzaCreator(1);
        Pizza combinationPizza1 = factory2.createPizza();
        combinationPizza1.eat();
            // 두개부턴 못먹어요 ㅜㅜ
        Pizza combinationPizza2 = factory2.createPizza();
        combinationPizza2.eat();
    }
}
반응형