디자인 패턴 - 팩토리 메서드 패턴

jihunnit·2022년 12월 23일
0
post-thumbnail

최근 velog 탐방을 하다가 디자인 패턴과 관련된 사이트
한글 번역이 됐다고 해서 이걸로 러프하게 디자인 패턴을
공부해 보고자 한다.

원래 이펙티브 자바를 통한 리팩토링을 할까 했으나, 디자인 패턴 등 기반 지식이 없으면 그 책은 읽을 필요가 없는 것 같았다.

디자인 패턴은 크게

  • 생성 패턴
  • 구조 패턴
  • 행동 패턴

으로 구성된다. 각자 이름과 깊은 관련이 있는 패턴들이다.
일단은 위 순서대로 다룰 예정이다.

첫 번쨰로 다룰 생성 패턴은 팩토리 메서드(Factory Method) 패턴이다.

이 패턴을 간단하게 설명하면, 제품을 찍어낼 공장의 형태를 제공한다. 이 공장은 큰 틀에서의 역할만 제공한다.

예를 들면, 공장은 과자 공장이다.
즉 과자를 생산할 수 있는 공장이지만, 진짜 어떤 과자를
생산할지에 대해서는 이 공장의 형태를 따르는 자식 클래스들이 결정을 한다.

어떤 공장은 비스킷, 어떤 공장은 쿠키 등등.. 원하는 바에 따라서 알아서 생성을 할 것이다.

핵심은, 여튼간에 이게 과자라면, 과자의 형태를 따르는 것 중 무언가를 생성할 수 있다는 것이다. 과자가 아닌 음료수처럼, 아예 역할이 다른 경우엔 생성할 수 없다.

구조는 다음과 같다.

특정 제품이라는 역할(인터페이스)와 이를 구현한 두 클래스에 대해, 이를 생성하는 creator라는 추상 클래스와 이를 구체화하는 두 클래스.
이 때, 추상 클래스는 생성을 했을 때 interface를 리턴하는 걸로 하고, 그래서 진짜 반환되는게 무엇인지는, 이 추상 클래스를 상속하고 구현한 클래스에서 결정짓는다.

백문이 불여일타. 코드로 작성해봤다.
(참고로 원문 사이트에 자바 코드가 훌륭하게 작성되어 있지만, 클론 코딩할 생각은 없어서 내가 직접 예시를 생각해봤다.)

일단 Member라는 interface가 존재한다. 이는 어찌됐든 사이트의 회원이라는 역할을 가진다.

package Entity;

public interface Member {
    void printClass();
}

간단하게 지금 클래스가 무슨 클래스인지 출력할 printClass를 가지고 있다.

이제, Member라는 역할은 사실 두 가지 구현체로 구현된다고 해보자.
운영자를 의미하는 MasterMember와, 손님을 의미하는 GuestMember
각자는 printClass를 구현하여, 자기가 어떤 클래스인지 출력한다.

//MasterMember.java
package Entity;

public class MasterMember implements Member{

    @Override
    public void printClass() {
        System.out.println("MASTER");
    }
}
package Entity;

public class GuestMember implements Member{

    @Override
    public void printClass() {
        System.out.println("GUEST");
    }
}

이렇게 팩토리의 생산 대상이 될 멤버들을 만들었다.

이제 멤버 생산을 담당할 팩토리들을 만들자.
먼저, Member interface를 반환하는 팩토리를
하나 만들어 보자
참고로, 이 팩토리는 생산을 담당할 생각은 없다.
생산과 관련한 틀을 잡아줄 뿐 이다.
실제 생산은 이 abstract class를 구현한 구현체가 담당한다.

//MemberFactory
package factory;

import Entity.Member;

public abstract class MemberFactory {

    public abstract Member createMember();
}

이제 실제 생산을 담당할 클래스들을 확인하자.

MasterMember를 생산할 MasterMemberFactory
GuestMember를 생산할 GuestMemberFactory가 있다.

//MasterMemberFactory
package factory;

import Entity.MasterMember;
import Entity.Member;

public class MasterMemberFactory extends MemberFactory{

    @Override
    public Member createMember() {
        return new MasterMember();
    }
}
//GuestMemberFactory
package factory;

import Entity.GuestMember;
import Entity.Member;

public class GuestMemberFactory extends MemberFactory{

    @Override
    public Member createMember() {
        return new GuestMember();
    }
}

이렇게 두 팩토리가 존재한다. 각 클래스는 본인이 생산을 담당한 Member 구현체를 new 를 이용해 반환한다.
이 부분이 사실 중요한데, 팩토리 메서드는 new를 생성 방식을 안쓰는게 목적이 아니다.
new를 이용한 객체의 생산을 특정 파트에서만 처리하도록 하는 것이다.

이제 마지막 main을 가 보자(테스트용으로 만든거라 조잡하다.)

import Entity.Member;
import factory.GuestMemberFactory;
import factory.MasterMemberFactory;
import factory.MemberFactory;

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        Member member = createMemberWithFactory(s);
        member.printClass();
    }
    public static Member createMemberWithFactory(String s){
        if(s.equals("guest")){
            MemberFactory mf = new GuestMemberFactory();
            return mf.createMember();
        }
        MemberFactory mf = new MasterMemberFactory();
        return mf.createMember();
    }
}

먼저 main method 에서는, 사용자에게 입력을 받고 이를 매개변수로 이용하여 팩토리를 생성하는 createMemberWithFactory를 호출한다.

createMemberWithFactory에서는, 사용자의 입력에 따라서
만약 입력이 "guest" 라면 GuestMemberFactory를,
아니라면 MasterMemberFactory를 생성하고,
createMember를 이용해 Member를 구현한 구현체를 반환한다.

결과를 확인하자.
(이 때, 입력은 "guest"와 "master"라는 올바른 두 입력 중 하나만 항상 들어온다고 가정하자)

이렇게, 나는 Member의 printClass를 호출했는데 각각 입력에 따라 Member를 구현한 구현체의 printClass가 호출되었다.

이를 통해, 요구사항(사용자의 입력)에 따라 다른 구현체를 생성했음을 볼 수 있다.

팩토리 메서드 패턴의 장단점은 무엇일까?

장점

  1. 런타임에 객체의 생성을 결정할 수 있다.
    -> 객체의 생성을 프로그램이 실행중일 때 받은 사용자의 요구사항에 따라 처리할 수 있다.

  2. 특정 interface를 구현한 구현체의 종류가 많을 때, 또한, 앞으로도 늘어날 가능성이 높다면, 이를 확장하는게 용이하다.
    -> 위에 예시에서, 나는 원래 있던 코드에서 아주 작은 부분을 제외하고는 거의 존재하던 코드를 수정하지 않고, 새로 코드를 추가함으로써 다른 멤버 구현체의 생산을 추가할 수 있다.

단점

복잡함

실제 사용 예시

실무에서 어떻게 쓰이는지에 대해 알아보다가, SSG.COM의 테크 블로그에서 이와 관련된 내용을 확인할 수 있었다.
궁금하신 분들은 참고하셔도 좋을 것 같다.

팩토리를 활용한 제휴사 관리법

이렇게
디자인패턴 중 생성 패턴의 첫 번째, 팩토리 메서드 패턴을 알아보았다.

이미지 출처
https://refactoring.guru/ko/design-patterns/factory-method

profile
인간은 노력하는 한 방황한다

0개의 댓글