FACTORY METHOD 패턴

박상준·2024년 3월 26일
0

디자인패턴

목록 보기
1/1

Factory Method 패턴

개요

Factory Method 패턴

  • 인스턴스 생성의 뼈대를 정의하고, 그 구체적인 구현을 하위 클래스에 위임하는 디자인 패턴이다.
  • 해당 패턴의 경우 Template Method 패턴의 인스턴스 생성 버전으로 볼 수 있다.

목적

  • 인스턴스 생성 과정의 틀을 상위 클래스에서 정의하고, 그 구체적인 내용은 하위 클래스에서 결정하게 함으로, 인스턴스 생성에 필요한 클래스와 인스턴스 생성 과정을 분리( decouple )한다.

예제 개요

프레임워크 패키지

  • Product 클래스
    • 모든 신분증(ID 카드) 의 추상 기반 클래스, 신분증에 공통적인 기능을 정의한다.
  • Factory 클래스
    • Product 인스턴스를 생성하는 추상 메서드를 선언한다.

idcard 패키지

  • IDCard 클래스
    • Product 클래스를 상속받아 실제 신분증의 구체적인 동작을 구현한다.
  • IDCardFactory 클래스
    • Factory 클래스를 상속받아 IDCard 인스턴스를 생성하는 구체적인 공장 역할을 한다.

Product 클래스

package factory_method.framework;

public abstract class Product {
    public abstract void use();
}
  • 목적
    • 제품 을 추상화한 클래스이다. use 라는 추상 메서드만을 선언하고 있다. 구체적인 use 의 구현은 Product 의 하위 클래스에서 담당한다.
  • 정의
    • 프레임워크에서 제품무엇이든지 사용할 수 있는 것 이다.

Factory 클래스

package factory_method.framework;

public abstract class Factory {
    public final Product create(String owner) {
        Product p = createProduct(owner);
        registerProduct(p);
        return p;
    }
    
    protected abstract Product createProduct(String owner);
    
    protected abstract void registerProduct(Product product);
}
  • 목적
    • 인스턴스 생성의 뼈대를 제공한다.
    • create 메서드는 createProduct - 상품 생성, registerProduct 를 통해 상품을 등록
  • 특징
    • Template Method 패턴이 사용된다.
    • createProductregisterProduct 추상 메서드로 구체적인 구현은 하위 클래스에서 담당한다.

IDCard 클래스

package factory_method.idcard;

import factory_method.framework.Product;

public class IDCard extends Product {
    private String owner;
    
    IDCard(String owner) {
        System.out.println(owner + "의 카드를 만듭니다.");
        this.owner = owner;
    }
    
    @Override
    public void use() {
        System.out.println(this + "을 사용합니다.");
    }
    
    @Override
    public String toString() {
        return "[IDCard:" + owner + "]";
    }
    
    public String getOwner() {
        return owner;
    }
}
  • idcard 의 소유자 정보를 저장하고, 카드의 사용 방법을 정의한다.

IDCardFactory 클래스

package factory_method.idcard;

import factory_method.framework.Factory;
import factory_method.framework.Product;

public class IDCardFactory extends Factory {
    @Override
    protected Product createProduct(String owner) {
        return new IDCard(owner);
    }
    
    @Override
    protected void registerProduct(Product product) {
        System.out.println(product + "을 등록합니다.");
    }
}

Factory 의 구체적인 구현으로서 IDCard 인스턴스를 생성, 생성된 인스턴스를 등록하는 역할을 한다.

Main

package factory_method;

import factory_method.framework.Factory;
import factory_method.framework.Product;
import factory_method.idcard.IDCardFactory;

public class Main {
    public static void main(String[] args) {
        Factory factory = new IDCardFactory();
        
        Product card1 = factory.create("홍길동");
        Product card2 = factory.create("이순신");
        Product card3 = factory.create("강감찬");
        
        card1.use();
        card2.use();
        card3.use();
    }
}

홍길동의 카드를 만듭니다.
[IDCard:홍길동]을 등록합니다.
이순신의 카드를 만듭니다.
[IDCard:이순신]을 등록합니다.
강감찬의 카드를 만듭니다.
[IDCard:강감찬]을 등록합니다.
[IDCard:홍길동]을 사용합니다.
[IDCard:이순신]을 사용합니다.
[IDCard:강감찬]을 사용합니다.

Factory Method 패턴의 등장인물

  1. Product ⇒ Product 클래스
    • 생성될 객체의 인터페이스를 정의
    • 프레임워크 측에서 해당 인터페이스를 제공하며, 구체적인 내용은 하위 클래스인 ConcreteProduct 에서 구현한다.
  2. Creator ⇒ Factory 클래스
    • 해당 역할은 Product 타입의 객체를 생성하는 추상클래스
    • 실제로 생성될 ConcreteProduct 에 대해 알지못한다.
      • 단지 인스턴스를 호출하면 Product 객체가 생성되는 것만 알고 있음.
  3. ConcreteProduct ⇒ IDCard 클래스
    • 이 역할은 실제 객체를 생성하는 클래스이다.
    • Product 인터페이스를 구현하거나 추상 클래스를 상속받아 구체적인 제품을 만듭니다.
  4. ConcreteCreator ⇒ IDCardFactory 클래스
    • 이 역할은 구체적인 제품을 생성하는 클래스이다.
    • Creator 클래스를 상속받아 createProduct 메소드를 구현하여 실제 제품을 생성합니다.

프레임워크와 구체적인 내용의 분리

  • framwork 의 경우
    • 일반적인 처리 흐름, 구조를 정의한다
      • 추상 클래스 혹은 인터페이스 형태로 제공된다.
      • 구체적인 처리 내용을 하위에 종속될 수 있기에 정의하지 않아야 한다.
    • framework 의 패키지 내용을 수정하지 않고 전혀 다른 제품 공장 을 만들 수 있는 장점이 있다.
  • concrete class의 경우
    • 프레임워크에 의해 정의된 구조나 흐름 내에서 실제로 수행될 구체적인 작업을 정의한다.

Java 에서 자주 활용되는 Static Factory Method

  • 인스턴스 생성을 위한 클래스 메서드(static 메서드) 를 의미한다.
  • 해당 방법은 Gof 의 Factory Method 와 다르다.
    • 하지만, Java 에서 매우 자주 활용되는 기법임.
    • Java 내부 API 에서도 볼 수 있다.
  • 예시
    1. java.security.SecureRandom의 getInstance 메소드
      • 난수 생성 알고리즘 이름을 지정해서 SecureRandom 인스턴스를 생성합니다.
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
    2. java.util.List의 of 메소드
      • 구체적인 요소를 주면 List 인스턴스를 생성합니다.
        List<String> list = List.of("Alice", "Bob", "Chris");
    3. java.time.Instant의 now 메소드
      • 현재 시간을 나타내는 Instant의 인스턴스를 생성합니다.
        Instant instant = Instant.now();

  • static method 의 경우 생성자로 단순히 만드는 것 보다 이점이 있음.
    • 생성자를 하나로 두고, 입구를 하나로 만듬
    • 하나인 입구에 대하여, 여러 파이프라인을 만든다.
      • 그 파이프라인이 static method 가 되며, 생성자보다 더 명확한 의미를 줄 수 있고 다양한 변환이 가능하다.
      • 또한 반환 타입의 하위 타입 객체를 반환할 수 있어 유연성이 높고, 메서드 이름을 통해 생성되는 객체의 특성을 명확하게 설명가능하다.
profile
이전 블로그 : https://oth3410.tistory.com/

0개의 댓글