[Java] 팩토리 메서드 패턴 정리

Kai·2023년 2월 16일
2

디자인 패턴

목록 보기
1/5

🧐 팩토리 메서드 패턴이란?


class Book {
	private String name;
    private Integer page;
    
    /* 생성자 생략 */
}

이러한 클래스가 있다고 가정해보자.
일반적으로 Book 인스턴스를 만들려고한다면, 아래와 같은 코드로 새로운 인스턴스를 생성할 것이다.

Book book = new Book();

그런데 팩토리 패턴은 내가 직접 인스턴스를 생성하지 않는다.
인스턴스를 생성해주는 팩토리 클래스를 하나 만들고 인스턴스를 생성하는 것은 팩토리 클래스가 대신해주게 된다.
"팩토리 메서드 패턴", 말 그대로 공장에서 물건을 찍어내는 개념이라고 볼 수 있다.

팩토리 메서드 패턴은 그냥 인스턴스를 생성하는 것에 비해 다양한 장점들을 갖고 있는데, 이 장점들을 이야기하기 전에 먼저 예제 코드로 팩터리 메서드 패턴이 어떤 것인지 알아보자.


💻 팩토리 메서드 패턴 준비


팩토리 메서드 패턴의 핵심은 인터페이스이다.

"책"이라는 인터페이스를 상속받아서 "만화책", "소설책" 클래스를 만들고, "책 공장"이라는 인터페이스를 상속받아서 "만화책 공장", "소설책 공장" 팩토리 클래스를 만드는 것이다.
즉, 구현체는 달라지지만 동일한 인터페이스들을 상속받기 때문에 실질적인 기능은 동일하게 된다.

말로 하니 뭔가 어려운 것 같은데... 😂
바로 예제로 알아보자!


Book 인터페이스

public interface Book {
    String getTitle();
    Integer getPage();
    String getBookInfo();
}

여러 종류의 책이 상속받을 Book 인터페이스이다.
이를 상속받아서 만화책, 소설책등등의 클래스를 만들 수 있다.

ComicBook 클래스

public class ComicBook implements Book {
    private final String title = "체인쏘맨";
    private final Integer page = 200;

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public Integer getPage() {
        return page;
    }

    @Override
    public String getBookInfo() {
        return "만화책:" + title + "/p." + page;
    }
}

Book 인터페이스를 상속받아서 만든 ComicBook이라는 클래스이다.


BookFactory 인터페이스

public interface BookFactory {
    Book publishBook();

    default void noticeToFan(String title) {
        System.out.println(title + "이 발매 됐습니다!");
    }
}

여러 종류의 책이 상속받을 Book 팩토리 인터페이스이다.
이를 상속받아서 만화책 팩토리, 소설책 팩토리등등의 팩토리 클래스를 만들 수 있다.

그리고 필요에 따라서 팩토리 클래스들에서 공통적으로 사용될 default메서드 또한 구현해주었다. 서로 다른 구현체로써 팩토리 클래스들은 만들어질 것이지만, 공통적으로 사용해야하는 기능이 있다면 이런식으로 구현해둘 수 있다.

ComicBookFactory

public class ComicBookFactory implements BookFactory {
    @Override
    public Book publishBook() {
        ComicBook comicBook = new ComicBook();
        // 만화책인 경우 팬들에게 알림을 준다고 가정한다. 🤭
        this.noticeToFan(comicBook.getTitle());
        return comicBook;
    }
}

BookFactory 인터페이스를 상속받아서 만든 ComicBookFactory이다.


Library

public class Library {
    private final Book book;

    public Library(BookFactory bookFactory) {
        this.book = bookFactory.publishBook();
    <}

    public boolean isOver100() {
        return book.getPage() > 100;
    }
}

책 공장에서 책을 받아서 어떠한 행동을 할 수 있는 "도서관"이라는 "클라이언트 클래스"를 만들었다.

이제 팩토리 메서드 패턴을 사용할 준비가 완료 됐다.
공장, 공장에서 찍어낼 물건, 그 물건을 사용할 곳이 준비가 된 것이다. 🤭
이제 팩토리 메서드 패턴이 어떻게 쓰이는지 알아보자.


💻 팩토리 메서드 패턴 예시


public class MainLogic {
    public static void main(String[] args) {
        BookFactory bookFactory = new ComicBookFactory();
        Library library = new Library(bookFactory);

        boolean over100 = library.isOver100();
        System.out.println("over100 = " + over100);
    }
}

예제 코드 자체는 매우 단순하다.
만화책 공장을 생성해서, Library에 넘겨주고, Library의 메서드를 실행해주는 코드이다.

⭐ 여기서 중요한 것이 2가지가 있다.

  1. ComicBookFactory의 인스턴스를 BookFactory 인터페이스를 타입으로 갖는 bookFactory로 할당했다는 것.
  2. 예제 코드에서는 보이지 않지만, ComicBookFactory에서 ComicBook 인스턴스를 만들 때, default메서드인 noticeToFan이 실행된다는 것.

이 2가지가 왜 중요하고, 어떤 장점을 가져다주는 것일까?


⭐ 팩토리 메서드 패턴을 쓰는 이유


위에서 이야기한 2가지 중요한 것은 각각 아래와 같은 의미를 갖는다.

  1. 기능이나 역할을 추상화함으로써 유연하게 확장할 수 있으면서, 각 구현체들의 무분별한 커스텀(?) 및 오남용을 막을 수 있다. Solid원칙 중, OCP에 해당하는 내용이다 ㅎㅎ
  2. 여러 구현체의 공통된 기능을 default 메서드 한 곳에서 처리함으로써 각 구현체들은 각자의 관심사에 집중되어 만들어질 수 있다.

흠... 글로 보니까 뭔가 어려운 것 같은데...
쉽게 이야기 하자면 객체 지향 프로그래밍답게 코딩을 할 수 있다는 것이다 🤭

이는 단순히 "객체 지향의 원칙을 지켰다"라는 의미가 아니고, 코드의 재사용성, 확장성, 안정성등을 아주 잘 보장해준다는 의미가 된다 👍


🍃 Spring 빈 팩토리


Spring 프레임워크는 객체 지향 프로그래밍을 극한으로 구현한 프레임워크이다. ㅎㅎ
Spring이 사용하는 개념 중에서 Bean Factory라는 것이 있는데, 이게 바로 팩토리 메서드 패턴을 극한으로 사용한 좋은 예시라고 할 수 있다.

0개의 댓글