알아두면 쓸데있는 IT 잡학사전

1. 개요

기존에 만들어진 복잡다난한 인스턴스의 내용이 일부만 살짝 변경된 비스무레한 객체가 필요한 경우에 쓰입니다. 일반적으로 객체를 새로 생성할 때는 new Object()와 같은 방법으로 생성을 합니다. 그러나 그렇게 생성할 경우 기존에 만들어진 것과 유사하다고 해도 결국 모든 정보를 다시 세팅해주어야 합니다. 그러나, clone()을 이용할 경우에는 기존에 만들어진 것을 복사해서 바뀐 부분만 대체해 주면 인스턴스를 생성하기가 쉽습니다. 아주 일반적인 "원형"을 만들어서 그것을 복사한 후 적당히 커스터마이징을 하면 new로 객체를 생성하는 것보다 쉽게 됩니다.


2. 예제

//---------------- 복잡한 정보를 가지고 있는 Complex -------------
package design.pattern.prototype;
import java.util.Date;
public class Complex implements Cloneable{
    private String complexInfo;

    private Date date;

    public Complex(String complexInfo) {
        this.complexInfo = complexInfo;
    }
    public String getComplexInfo() {
        return complexInfo;
    }
    public void setDate(Date date){
        this.date = new Date(date.getTime());
    }
    public Date getDate() {
        return date;
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        Complex tmp = (Complex) super.clone();
        return tmp;
    }
}
//---------------- 복사를 실행하는 테스트 클래스 -------------
package design.pattern.prototype;
import java.util.Date;
public class Test {
    public static void main(String[] args) {
        Complex com = new Complex("매우 복잡한 정보");
        try {
            Complex cloned1 = (Complex)com.clone();
            cloned1.setDate(new Date(2008,0,1));

            Complex cloned2 = (Complex)com.clone();
            cloned2.setDate(new Date(2008,2,1));
            
            System.out.println(cloned1.getDate());
            System.out.println(cloned2.getDate());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

//---------------- 테스트 결과 -------------
Wed Jan 01 00:00:00 KST 3908
Sun Mar 01 00:00:00 KST 3908

테스트 클래스에는 변수가 3개 등장합니다. com과 cloned1, clone2 입니다. 셋다 Complex 클래스의 인스턴스 들입니다.

com은 소스코드에서는 매우 쉽게 생성해냈지만, 생성하는 과정이 매우 복잡하며, 멤버 변수로 매우 복잡한 것들을 가지고 있다고 가정합니다. 그래서 다시 한 번 똑같은 것을 만들어 내기가 매우 어렵다고 가정합시다.

그렇게 어렵게 만들어진 com과 다 똑같은 데 멤버 변수 한 두개만 다른 값을 가지는 객체를 만들고 싶습니다. cloned1과 cloned2가 바로 그런 인스턴스들입니다. com이 바로 원형이 되는 것이고, cloned1과 cloned2는 그 원형에서 복사해서 만들어진 객체들이며, 실제로 뭔가를 하는 것은 cloned1, cloned2 입니다. com은 cloned1,cloned2를 찍어내기 위한 원형일 뿐입니다.


3. Prototype 용도 및 일반적인 구현

스타크래프트 같은 걸 생각을 해봅시다. 건물은 Building 이라는 클래스 하나로 정의된다고 칩시다. 한 명의 플레이어는 커맨드 센터를 여러 개 지을 수 있습니다. 각각의 커맨드 센터끼리는 위치 등 일부 정보만 다르고 생김새, 기본 에너지 등등 다른 건 다 비슷 할 것 입니다. 그럴 때 Building이라는 클래스의 속성으로 모든 값들을 다시 세팅하는 것은 굉장히 번거로운 작업이 될 겁니다. 그래서 대략적인 모양새를 갖춘 객체를 하나 생성하고 그 객체를 복사해서 필요한 필드만 다시 세팅하면 쓸만한 커맨드 센터가 만들어집니다.

또 위의 예제에서는 그렇게 구현하지 않았지만 일반적으로 Prototype은 외부로 드러내지 않습니다. 팩토리 패턴과 조합해서 쓰는 게 일반적입니다. Factory 클래스에서 원형을 관리하고, 그 Factory의 create method가 호출되면, 원형으로부터 복사해서 외부로 던져주는 겁니다. Prototype은 Factory에서만 관리되고 그 외부로 드러나지 않습니다.

clone() method가 호출되어 새로운 객체가 생성되는 시점에 원형이 어찌 생겼는지 크게 신경쓰지 않습니다. 그냥 복사 할 뿐입니다.

'개발 > JAVA' 카테고리의 다른 글

[Design Pattern]Builder  (0) 2018.07.17
[Design Pattern]Flyweight  (0) 2018.07.16
[Design Pattern]Observer  (0) 2018.07.16
[Design Pattern]Facade  (0) 2018.07.16
[Design Pattern]Composite  (0) 2018.07.16