개념

 java로 새로운 인스턴스를 생성할 때 기본적으로 new 클래스명() 과 같은 키워드로 생성한다. 하지만 클래스명을 따로 지정하지 않고 기존의 있는 인스턴스를 복사해서 새로운 인스턴스를 생성하는 것이 유리한 경우가 존재한다.

  • 개체의 종류가 너무 다양해서 클래스가 너무 많은 경우.
  • 생성 과정이 복잡한 클래스로 사용자가 인스턴스 생성에 많은 비용이 드는 경우
  • 인스턴스 생성과 framework를 분리하고 싶은 경우

이러한 경우 사용이 유리한 것이 Prototype 패턴이다. 간단히 말해 기초가 되는 인스턴스를 기준으로 복제해서 인스턴스를 생성하는 패턴이라 보면 된다.

 

 

역할

Prototype 역할

  인스턴스를 복사하는 메서드를 정한다. 예제에서는 Product interface.

 

ConcretePrototype 역할

  인스턴스 복사로 새로운 인스턴스를 생성하는 메서드를 구현한다. 예제에서는 MessageBox 클래스와 UnderlinePen 클래스.

 

Client 역할

  인스턴스를 복사하는 메서드를 사용해서 새로운 인스턴스를 만드는 이용자. 예제에서는 Manager 클래스.

 

 

이득 및 유의사항

Prototype(예제에서는 Product interface)이나 Client(예제에서는 Manage 클래스)에서는 ConcretePrototype 클래스명이 전혀 나오지 않아야 한다. 그래야 Client에 어떤 ConcretePrototype의 인스턴스가 전달 되든지 상관없이 독립적으로 코딩이 가능하다. Client와 ConcretePrototype 간에는 직접적인 연결이 없이 Prototype만이 인터페이스가 된다.

 

 소스 코드에 직접적으로 어떠한 클래스 이름이 적혀 있다면 클래스(모듈)간 결합도가 높아질 수 밖에 없고, 결과적으로 재사용성이 떨어질 수 밖에 없다. Prototype 패턴을 사용하는 것도 결합도를 낮추고 재사용성을 높이기 위한 것이다.

 

 clone() 메서드를 사용하기 위해선 Cloneable interface를 상속해야 하는데, clone() 메서드 자체는 java.lang.Object 패키지에 정의되어 있다. Cloneable interface는 그저 clone이 가능한 클래스임을 표시해주는 maker interface의 역할을 할 뿐이다.

 clone() 메서드의 동작은 기존 인스턴스와 동일한 크기의 메모리를 할당하고 필드를 복사하는 역할을 하는데, 얉은 복사가 되기 때문에 깊은 복사를 원한다면 clone() 메서드를 오버라이드 해줘야 한다.

 clone() 메서드를 오버라이드 할 경우 super.clone() 으로 상위 클래스의 clone() 메서드도 호출되도록 해야한다.

 

예제 코드

//Prototype
package prototype.framework;

public interface Product extends Cloneable{
	public abstract void use(String s);
	public abstract Product createClone();
}


//ConcretePrototype1
package prototype;

import prototype.framework.Product;

public class MessageBox implements Product{
	private char decochar;
	public MessageBox(char decochar) {
		this.decochar = decochar;
	}
	
	public void use(String s) {
		int length = s.getBytes().length;
		for(int i=0; i<length+4; i++) {
			System.out.print(decochar);
		}
		System.out.println(" ");
		System.out.println(decochar + " " + s + " " + decochar);
		for(int i=0; i<length+4; i++) {
			System.out.print(decochar);
		}
		System.out.println(" ");
	}
	
	public Product createClone() {
		Product p = null;
		try {
			p = (Product)clone();
		} catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return p;
	}
}


//ConcretePrototype2
package prototype;

import prototype.framework.Product;

public class UnderlinePen implements Product{
	private char ulchar;
	public UnderlinePen(char ulchar) {
		this.ulchar = ulchar;
	}
	
	public void use(String s) {
		int length = s.getBytes().length;
		System.out.println("\""+ s + "\"");
		System.out.print(" ");
		for(int i=0; i<length; i++) {
			System.out.print(ulchar);
		}
		System.out.println(" ");
	}
	
	public Product createClone() {
		Product p = null;
		try {
			p = (Product)clone();
		} catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return p;
	}
}


//Client
package prototype.framework;

import java.util.HashMap;

public class Manager {
	private HashMap<String, Product> showcase = new HashMap<>();
	public void register(String name, Product proto) {
		showcase.put(name, proto);
	}
	
	public Product create(String protoname) {
		Product p = (Product)showcase.get(protoname);
		return p.createClone();
	}
}


//Tester
package prototype;

import prototype.framework.Manager;
import prototype.framework.Product;

public class PrototypeTester {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Manager manager = new Manager();
		UnderlinePen upen = new UnderlinePen('~');
		MessageBox mbox = new MessageBox('*');
		MessageBox sbox = new MessageBox('/');
		
		manager.register("strong message", upen);
		manager.register("warning box", mbox);
		manager.register("slash box", sbox);
		
		Product p1 = manager.create("strong message");
		p1.use("Hello, world");
		
		Product p2 = manager.create("warning box");
		p2.use("Hello, world");
		
		Product p3 = manager.create("slash box");
		p3.use("Hello, world");
	}

}

 

'디자인 패턴' 카테고리의 다른 글

8. AbstractFactory 패턴  (0) 2020.12.07
7. Builder 패턴  (0) 2020.12.04
5. Singleton 패턴  (0) 2020.12.02
4. FactoryMethod 패턴  (0) 2020.12.01
3. Template Method 패턴  (0) 2020.11.30

+ Recent posts