[GoF] Factory Method 패턴

패턴명칭

Factory Method

필요한 상황

객체의 생성에 대해 Template 패턴을 활용한 경우이다. 객체를 안전하고 완벽하게 생성하기 위한 방법을 상위 클래스에서 정해 놓고, 그 방법에 대한 구체적인 구현은 하위 클래스에서 정의한다.

예제 코드

다양한 형태의 도형을 생성을 위해 필요한 절차를 Factory 클래스에 정의해 놓고, 각 절차에 대한 구체적인 구현은 SyncFactory 클래스에서 정의한다. 먼저 Factory 클래스는 다음과 같다.

package tstThread;

public abstract class Factory {
	public Shape create(Shape newShape) {
		if(register(newShape)) {
			if(uploadToServer(newShape)) {
				return newShape;
			}
		}
		
		return null;
	}
	
	protected abstract boolean register(Shape shape);
	protected abstract boolean uploadToServer(Shape shape);
}

먼저 생성된 초벌 객체를 인자로 받아 등록하고, 서버로 해당 도형을 전송까지 성공하면 처리된 객체를 반환하지만 절차중 하나라도 실패하면 null을 반환한다. 초벌 객체의 생성은 인자로 받았으나 create 매서드 내부에서 수행해도 된다. 완전한 객체 생성을 위한 절차를 구체적으로 구현한 SyncFactory 클래스는 다음과 같다.

package tstThread;

import java.util.HashMap;

public class SyncFactory extends Factory {
	private HashMap<String, Shape> shapes = new HashMap<String, Shape>();

	@Override
	protected boolean register(Shape shape) {
		String name = shape.getName();
		
		if(!shapes.containsKey(name)) {
			shapes.put(name, shape);
			System.out.println("registering shape(" + shape + ") is successed.");
			return true;
		}
		
		System.out.println("registering shape(" + shape + ") is failed.");
		return false;
	}

	@Override
	protected boolean uploadToServer(Shape shape) {
		try {
			Thread.sleep(1000);
			System.out.println("uploading shape(" + shape + ") is successed.");
			return true;
		} catch(Exception e) {
			System.out.println("uploading shape(" + shape + ") is failed.");
			return false;
		}		
	}
}

다음은 생성할 도형에 대한 Shape 클래스이다.

package tstThread;

public abstract class Shape {
	protected String name;
	
	public Shape(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public String toString() {
		return name;
	}
	
	public abstract void draw();
}

이 Shape 클래스를 구현한 구체적인 파생 클래스 중 Circle 클래스는 다음과 같다.

package tstThread;

public class Circle extends Shape {
	private int radius;
	
	public Circle(String name, int radius) {
		super(name);
		this.radius = radius;
	}

	@Override
	public void draw() {
		System.out.println("Circle(" + name + ") draw : radis = " + radius);
	}
}

Box 클래스는 다음과 같다.

package tstThread;

public class Box extends Shape {
	private int width;
	private int height;
	
	public Box(String name, int width, int height) {
		super(name);
		this.width = width;
		this.height = height;
	}

	@Override
	public void draw() {
		System.out.println("Circle(" + name + ") draw : width = " + width + ", height = " + height);
	}
}

지금까지 만든 클래스를 사용하는 코드는 다음과 같다.

package tstThread;

public class Main {
	public static void main(String[] args) {
		Factory factory = new SyncFactory();
		Shape shape;
		
		shape = factory.create(new Circle("SHAPE1", 10));
		if(shape != null) shape.draw();
		System.out.println();
		
		shape = factory.create(new Box("SHAPE2", 10, 20));
		if(shape != null) shape.draw();
		System.out.println();
		
		shape = factory.create(new Box("SHAPE1", 5, 10));
		if(shape != null) shape.draw();
		System.out.println();
	}
}

실행결과는 다음과 같다.

registering shape(SHAPE1) is successed.
uploading shape(SHAPE1) is successed.
Circle(SHAPE1) draw : radis = 10

registering shape(SHAPE2) is successed.
uploading shape(SHAPE2) is successed.
Circle(SHAPE2) draw : width = 10, height = 20

registering shape(SHAPE1) is failed.

총 3개의 도형을 생성했는데, 마지막 도형의 경우 이미 동일한 이름(name)을 갖고 도형이 먼저 생성되어져 있어 실패하게 된다.

이 글은 소프트웨어 설계의 기반이 되는 GoF의 디자인패턴에 대한 강의자료입니다. 완전한 실습을 위해 이 글에서 소개하는 클래스 다이어그램과 예제 코드는 완전하게 실행되도록 제공되지만, 상대적으로 예제 코드와 관련된 설명이 함축적으로 제공되고 있습니다. 이 글에 대해 궁금한 점이 있으면 댓글을 통해 남겨주시기 바랍니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다