[DesignPattern] 팩토리 메서드 패턴

팩토리 메서드 패턴


팩토리 메서드 패턴에서는 상위 클래스에서 처리의 골격을 만들고, 하위 클래스에서 구체적인 처리의 내용을 만들었다. 이 패턴을 인스턴스 생성의 장면에 적용한 것이 바로 팩토리 메서드 패턴이다. factory는 공장이라는 의미이다. 인스턴스를 생성하는 공장을 템플릿 메서드 패턴으로 구성한 것이 팩토리 메서드 패턴이다. 즉, 팩토리 메서드 패턴을 사용하면 객체 생성 기능을 제공하는 Factory 클래스를 정의하고 이를 활용하는 방식으로 설계하면 된다.

펙토리 메서드 패턴에서는 인스턴스를 만드는 방법을 상위 클래스 측에서 결정하지만 구체적인 클래스 이름까지는 결정하지 않는다. 따라서 인스턴스 생성을 위한 골격과 실제의 인스턴스 생성의 클래스를 분리해서 생각할 수 있다.

cp.) 팩토리 메서드 패턴은 객체의 생성 코드를 별도의 클래스/메서드로 분리함으로써 객체 생성의 변화에 대비하는 데 유용하다. 또한 팩토리 메서드 패턴은 객체 생성을 전담하는 별도의 클래스를 두는 대신 하위 클래스에서 적합한 클래스의 객체를 생성하는 방식으로도 적용할 수 있다.


▶ 등장인물

 패키지 

 이름

 해설

 framework

 Product

 추상메서드 use만 정의되어 있는 추상 클래스

 Factory

 메서드 create을 구현하고 있는 추상 클래스

 idcard

 IDCard

 메서드 use를 구현하고 있는 클래스

 IDCardFactory

 메서드 createProduct, registerProduct를 구현하고 있는 클래스

 Anonymous

 Main

 동작 테스트용 클래스


▶ 예제 프로그램 해설

아래의 예제 프로그램에서는 신분증명서 카드(ID 카드)를 만드는 공장을 소재로 하였다. 여기에는 다섯 개의 클래스가 있다. Product 클래스와 Factory 클래스는 framework라는 패키지에 속해 있다.

이 두 개의 클래스가 인스턴스 생성을 위한 골격(framework)의 역할을 한다.

IDCard 클래스와 IDCardFactory 클래스는 구체적인 내용을 구현하며 idcard라는 패키지에 속해 있다.

Main 클래스는 동작 테스트를 위한 클래스이다.


1. Product: 팩토리 메서드로 생성될 객체의 공통 인터페이스

- Product(제품)의 역할: 이것은 framework 쪽에 포함되어 있다. 이 패턴에서 생성되는 인스턴스가 가져야 할 인터페이스를 결정하는 것은 추상 클래스이다.

구체적인 내용은 하위 클래스의 ConcreateProduct 역할이 결정한다.

package framework;


public abstract class Product {

    public abstract void use();

}

framework 패키지의 Product 클래스는 '제품'을 표현한 클래스이다. 이 클래스에는 추상 메서드 use만이 선언되어 있다.

구체적인 use의 구현은 모두 Product의 하위 클래스에게 맡기고 있다.

이 framework에서는 제품이란 '무엇이든 use할 수 있는(사용할 수 있는) 것'으로 규정하고 있다.


2. Factory: 구체적으로 객체가 생성되는 클래스

- Creator(작성자)의 역할: Product 역할을 생성하는 추상 클래스는 framework 쪽에 가깝다. 구체적인 내용은 하위 클래스의 ConcreateCreator 역할이 결정한다.

Creator 역할은 실제로 생성하는 ConcreateProduct 역할에 가지고 있는 정보가 없다. Creator 역할이 가지고 있는 정보는 Product 역할과 인스턴스 생성의 메소드를 호출하면 Product가 생성된다는 것뿐이다. 예제 프로그램에서는 createProduct 메서드가 인스턴스 생성을 위한 메서드가 된다.

new를 사용해서 실제의 인스턴스를 생성하는 대신에, 인스턴스 생성을 위한 메서드를 호출해서 구체적인 클래스 이름에 의한 속박에서 상위 클래스를 자유롭게 만든다.

package 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);

}

framework 패키지의 Factory 클래스에서는 템플릿 메서드 패턴이 사용되고 있다.

추상 메서드 createProduct에서는 '제품을 만들고', 만든 제품을 추상 메서드 registerProduct에서 '등록'한다. '제품을 만들고', '등록'하는 구현은 하위 클래스에서 수행한다.

이 framework에서 공장이란 'create 메서드에서 Product의 인스턴스를 생성하는 것'으로 규정하고 있다.

그리고 create 메서드는 'createProduct에서 제품을 만들어서 registerProduct에서 등록한다.'라는 순서로 구현되고 있다.

구체적인 구현 내용은 Factory Method 패턴을 적용한 프로그램에 따라 다르다. Factory Method 패턴에서는 인스턴스를 생성할 때 Templete Method 패턴을 사용한다.


3. IDCard: 구체적으로 객체가 생성되는 클래스

- ConcreateProduct(구체적인 제품)의 역할: 구제적인 제품을 결정하며, idcard 쪽에 해당된다.

package idcard;

import framework.*;


public class IDCard extends Product {

    private String owner;

    IDCard(String owner) {

        System.out.println(owner + "의 카드를 만듭니다.");

        this.owner = owner;

    }

    public void use() {

        System.out.println(owner + "의 카드를 사용합니다.");

    }

    public String getOwner() {

        return owner;

    }

}

내용을 실행하는 측(idcard 패키지)을 살펴보자. 인식번호 카드를 나타내는 IDCard라는 클래스를 만들어보자.

framework에서 분리된 것을 표시하기 위해 idcard 패키지라는 별도의 패키지를 만들고, IDCard 클래스를 제품 product 클래스의 하위 클래스로 정의한다.


4. IDCardFactory: 팩토리 메서드를 구현하는 클래스로 ConcreateProduct 객체를 생성한다.

- ConcreateCreator(구체적인 작성자)의 역할: 구체적인 제품을 만드는 클래스를 결정하며, idcard 쪽에 해당된다.

package idcard;

import framework.*;

import java.util.*;


public class IDCardFactory extends Factory {

    private List owners = new ArrayList();

    protected Product createProduct(String owner) { // 인스턴스 생성을 위한 메서드

        return new IDCard(owner);// IDCard의 인스턴스를 생성해서 제품을 만드는 일을 실현

// new를 사용해서 실제 인스턴스를 사용하는 대신에, 인스턴스 생성을 위한 메서드를 호출해서 

// 구체적인 클래스 이름에 의한 속박에서 상위클래스를 자유롭게 만든다.

    }

    protected void registerProduct(Product product) {

        owners.add(((IDCard)product).getOwner());

    }

    public List getOwners() {

        return owners;

    }

}

IDCardFactory 클래스에서는 createProduct와 registerProduct의 두 가지 메서드를 구현하고 있다. createProduct에서는 IDCard의 인스턴스를 생성해서 '제품을 만드는'을 실현하고 있다.

registerProduct에서는 IDCard의 owner(소유자)를 owners 필드를 추가해서 '등록'이라는 기능을 실현하고 있다.


5. Main

import framework.*;

import idcard.*;


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();

    }

}

실행결과)

홍길동의 카드를 만듭니다.

이순신의 카드를 만듭니다.

강감찬의 카드를 만듭니다.

홍길동의 카드를 사용합니다.

이순신의 카드를 사용합니다.

강감찬의 카드를 사용합니다.