디자인패턴

[디자인패턴] 생성 패턴 - 팩토리 메소드(Factory method) 패턴

swimKind 2022. 8. 23. 22:56

[디자인패턴] 생성 패턴 - 팩토리 메소드(Factory method) 패턴

 

 

 

*팩토리 메소드 패턴

- 구체적으로 어떤 인스턴스를 만들지 서브 클래스에서 정하게 한다.

  • 다양한 구현체(Product)가 있고, 그 중에서 특정한 구현체를 만들 수 있는 다양한 팩토리(Creator)를 제공할 수 있다.

- 확장엔 열려있고 변경엔 닫혀있는 OCP(Open Closed Principle)에 부합한다. 

 

 

 

 

 

예를 들어

 

HairDesigner(Creator)와 HairDye(Product)로 팩토리 메소드 패턴을 구현한다면

 

 

- Product

package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

import lombok.Getter;
import lombok.Setter;

@Getter @Setter
public class HairDye {
    private String colorNameKr;
    private String colorNameEn;
    private String colorCode;

    @Override
    public String toString() {
        return "사용된 염색약은 " +
                colorNameKr +
                "(" + colorNameEn + "), " +
                "code: " + colorCode +
                " 입니다";
    }
}

팩토리 메소드 패턴에서 Product, 팩토리에서 만들어 낼 데이터 오브젝트이다.

 

 

- concreteProductor

package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

public class DarkHairDye extends HairDye{
    public DarkHairDye() {
        setColorCode("2N");
        setColorNameEn("Dark");
        setColorNameKr("흑색");
    }
}
package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

public class BrownHairDye extends HairDye{
    public BrownHairDye() {
        setColorCode("5N");
        setColorNameEn("Brown");
        setColorNameKr("자연갈색");
    }
}

Product의 규격은 같으면서 다른 값들의 오브젝트를 구체화한다.

 

 

- Creator

package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

public interface HairDesigner {
    default HairDye dying(String color, int time) {
        validate(color);
        selectedDesigner();
        HairDye hairDye = dyingService();
        spreadHairDye(color);
        waitFor(time);
        return hairDye;
    }

    void selectedDesigner();

    HairDye dyingService();

    private void validate(String color) {
        if (color == null || color.isBlank()) {
            throw new IllegalArgumentException("색상이 선택되지 않았습니다");
        }
    }

    private void spreadHairDye(String color) {
        System.out.println(color + " 염색약을 바릅니다");
    }

    private void waitFor(int time) {
        System.out.println(time + "분간 기다립니다");
    }
}
package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

public abstract class DefaultHairDesigner implements HairDesigner {
    public void selectedDesigner() {
        System.out.println("일반 디자이너 선생님이 작업합니다.");
    }
}

Product를 사용할 팩토리(Creator)의 기본적인 규격을 정해놓은 추상화된 객체이다. DefaultHairDesigner 같은 추상 클래스의 경우는 사용해도 되고 사용하지 않아도 된다. 추가적으로 디자이너를 선택할 수 있는 기능이 추가되면 파라미터로 변경할 수 있게 만들어도 된다. java 9 버전부터 interface에서 private 제한자를 사용할 수 있지만, 하위 버전에선 사용할 수 없다. 

 

 

- ConcreteCreator

package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

public class DarkHairDesigner extends DefaultHairDesigner {
    @Override
    public HairDye dyingService() {
        return new DarkHairDye();
    }
    
}
package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

public class BrownHairDesigner extends DefaultHairDesigner {
    @Override
    public HairDye dyingService() {
        return new BrownHairDye();
    }
}

팩토리(Creator)에서 추상화된 구현체를 구체화 한다. 각각의 클래스가 정해진 기능만을 수행할 수 있도록 한다.

 

 

- Client

package me.whiteship.designpatterns._01_creational_patterns._02_factory_method.practice;

public class Client {
    public static void main(String[] args) {
        Client client = new Client();
        client.print(new DarkHairDesigner(), "검정색", 40);
        client.print(new BrownHairDesigner(), "갈색", 30);
    }
//        일반 디자이너 선생님이 작업합니다.
//        검정색 염색약을 바릅니다
//        40분간 기다립니다
//        사용된 염색약은 흑색(Dark), code: 2N 입니다

//        일반 디자이너 선생님이 작업합니다.
//        갈색 염색약을 바릅니다
//        30분간 기다립니다
//        사용된 염색약은 자연갈색(Brown), code: 5N 입니다

    private void print(HairDesigner hairDesigner, String color, int time) {
        System.out.println(hairDesigner.dying(color, time));
    }
}

사용자(Client)가 팩토리 메소드 패턴을 통해서 동일한 규격의 다른 데이터들을 구현할 수 있다.

 

 

 

 

팩토리 메소드 패턴은 팩토리(Creator)가 특정한 구현체(Product)를 다양한 방법으로 구현할 수 있다. 또한 기존의 팩토리(DarkHairDesigner, BrownHairDesigner) 뿐만 아니라 추가적인 팩토리(ex. YellowHairDesigner)를 만들 수 있으며(Open) 추가 하더라도 기존의 코드를 변경 또는 수정하지 않을 수 있다.(Closed)

하지만 단점으로, 기능을 계속 추가하게 되면 각자의 역할이 세분화 되어있기 때문에 클래스가 늘어나는 부분이 생긴다.

 

 

 

https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4

 

코딩으로 학습하는 GoF의 디자인 패턴 - 인프런 | 강의

디자인 패턴을 알고 있다면 스프링 뿐 아니라 여러 다양한 기술 및 프로그래밍 언어도 보다 쉽게 학습할 수 있습니다. 또한, 보다 유연하고 재사용성이 뛰어난 객체 지향 소프트웨어를 개발할

www.inflearn.com