new라는 키워드를 사용해 새로운 인스턴스를 생성하는 것이 아닌, 원래 있는 인스턴스로 부터 복사해서 새로운 인스턴스를 만드는 것.
필요한 경우는 3가지가 있다.
1. 종류가 너무 많아 클래스로 정리하지 않은 경우
2. 클래스로부터 인스턴스 생성이 어려운 경우
3. Framework와 생성할 인스턴스를 분리하고 싶은 경우
: 클래스 이름을 지정해서 인스턴스를 만드는 것이 아닌, '모형' 인스턴스를 등록해놓고 그 인스턴스를 복사해서 인스턴스를 생성해서 사용.
public interface Product extends Cloneable {
public abstract void use(String s);
public abstract Product createCopy();
}
Cloneable을 사용하면 clone 메소드를 사용하여 자동적으로 인스턴스 복제가 가능하다.
public class Manager {
private Map<String,Product> showcase = new HashMap<>();
public void register(String name, Product prototype) {
showcase.put(name, prototype);
}
public Product create(String prototypeName) {
Product p = showcase.get(prototypeName);
return p.createCopy();
}
}
Product를 생성함으로써 구현체를 모르도록 가능하다. 즉 Product 구현체에 의존하지 않는다.
public class MessageBox implements Product {
private char decochar;
public MessageBox(char decochar) {
this.decochar = decochar;
}
// 복사 생성자
public MessageBox(MessageBox prototype) {
this.decochar = prototype.decochar;
}
@Override
public void use(String s) {
int decolen = 1 + s.length() + 1;
for (int i = 0; i < decolen; i++) {
System.out.print(decochar);
}
System.out.println();
System.out.println(decochar + s + decochar);
for (int i = 0; i < decolen; i++) {
System.out.print(decochar);
}
System.out.println();
}
@Override
public Product createCopy() {
return new MessageBox(this);
}
}
public class UnderlinePen implements Product {
private char ulchar;
public UnderlinePen(char ulchar) {
this.ulchar = ulchar;
}
// 복사 생성자
public UnderlinePen(UnderlinePen prototype) {
this.ulchar = prototype.ulchar;
}
@Override
public void use(String s) {
int ulen = s.length();
System.out.println(s);
for (int i = 0; i < ulen; i++) {
System.out.print(ulchar);
}
System.out.println();
}
@Override
public Product createCopy() {
return new UnderlinePen(this);
}
}
public class Main {
public static void main(String[] args) {
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.");
}
}
Prototype의 역할 : Product 인터페이스가 이 역할을 하며, 인스턴스를 복사하여 새로운 인스턴스를 만들기 위한 메소드를 결정
ConcretePrototype(구체적인 원형)의 역할 : 실제로 인스턴스를 복사해서 새로운 인스턴스를 만들어 내는 메소드를 구현해낸다. 예제에서는 MessageBox 클래스와 UnderlinePen 클래스이다.
Client(이용자)의 역할 : Manager 클래스가 이 역할을 하며, 실제로 copy 해낸다. 이 예제에서는 등록과 제작이 가능하도록 했다.
public class Employees implements Cloneable {
private List < String > empList;
public Employees() {
empLisy = new ArrayList < > ();
}
public Employees(List < String > list) {
this.empList = list;
}
public void loadData() {
empList = empRepository.findAll();
예시과 같이 디비에서 가져오기
}
@Override
public Object clone() throws CloneNotSupportedException {
List < String > temp = new ArrayList < > ();
for (String str: this.empList) {
temp.add(str);
}
return new Employees(temp);
}
}
public class PrototypePattern {
public static void main(String[] args) throws CloneNotSupportedException {
Employees emps = new Employees();
emps.loadData(); // Ann, John, Methew...
Employees emps1 = (Employees) emps.clone();
Employees emps2 = (Employees) emps.clone();
List < String > list1 = emps1.getEmpList();
list1.add("Peter");
List < String > list2 = emps2.getEmpList();
list2.remove("John");
System.out.println("emps: " + emps.getEmpList());
System.out.println("emps1: " + list1.getEmpList());
System.out.println("emps2: " + list2.getEmpList());
}
}
참조 : https://velog.io/@newtownboy/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85%ED%8C%A8%ED%84%B4Prototype-Pattern
Java 언어로 배우는 디자인 패턴 입문