CS/디자인패턴
[디자인 패턴][생성 패턴] - 프로토타입 패턴
흰무
2023. 6. 13. 14:37
1. 프로토타입 패턴
객체를 생성하는데 비용이 많이 들고, 비슷한 객체가 이미 있을 때 사용되는 패턴
원본 객체를 새로운 객체에 복사하여 필요에 따라 수정하는 메커니즘을 제공하는 패턴
- 사용하는 경우
- 종류가 너무 많아 클래스로 정리할 수 없는 경우 => 소스파일을 줄일 수 있다
- 클래스로부터 인스턴스 생성이 어려운 경우 => 이미 한번 복잡한 과정을 거쳐 만들어진 인스턴스 활용 가능(과정 생략)
- 프레임워크와 생성하는 인스턴스를 분리하고 싶은 경우 => 등록된 인스턴스를 복사해서 생성하기 때문에, 프레임워크와 분리
- 구현 방법
Java의 경우, Java에서 제공하는 Clone 메소드와 Cloneable 인터페이스를 사용해 구현한다.
- 예제
Product 인터페이스 = Prototype
Mananger 클래스 = Client
MessageBox, UnderlinePen 클래스 = ConcretePrototype1,2
## Product 인터페이스
public interface Product extends Cloneable {
public abstract void use(String s);
public abstract Product createCopy();
}
## Mananger 클래스
## Product 인터페이스를 이용해 인스턴스를 복제
## import 생략
public class Manager {
private Map<String,Product> showcase =. ew 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();
}
}
## MessageBox 클래스
## Product 인터페이스를 구현
## use 메소드는 주어진 문자열을 decochar로 감싼다
## createCopy 메소드는 자기 자신을 복제하는 메소드
## clone 메소드는 자신의 클래스에서만 호출할 수 있으므로
## 다른 클래스의 요청으로 복제할 경우 createCopy와 같은 별도의 메소드가 필요!
public class MessageBox implements Product {
private char decochar;
public MessageBox(char decochar) {
this.decochar = 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(dechchar);
}
System.out.println();
}
@Override
public Product createCopy() {
Product p = null;
try {
p = (Product)clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
## UnderlinePen 클래스
## MessageBox와 같은 동작을 하나, 주어진 문자열을 감싸는 것이 아닌, 밑줄만 생성
public class UnderlinePen implements Product {
private char ulchar;
public UnderlinePen(char ulchar) {
this.ulchar = ulchar;
}
@Override
public void use(String s) {
int ullen = 1 + s.length() + 1;
System.out.println(s);
for (int i = 0; i < ullen; i++) {
System.out.print(ulchar);
}
System.out.println();
}
@Override
public Product createCopy() {
Product p = null;
try {
p = (Product)clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
## Main 클래스
## 위의 인터페이스와 클래스들을 활용해 인스턴스를 생성/복제
public class Main {
public static void main(String[] args) {
// 준비
Manager mananger = 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 = manger.create("slash box");
p3.use("Hello, world.");
}
}
위의 Main 클래스를 실행하면, p1,p2,p3 모두 인스턴스가 복제되어 생성되는 것을 확인할 수 있다.
- 의문점?
왜 이렇게 소스 코드 안의 클래스 이름을 쓰지 않고 분리하기 위해 노력하는 걸까?
=> 객체지향 프로그래밍의 목표 중 하나가 "부품으로서의 재사용"이기 때문
=> 소스 코드 안에 이용할 클래스의 이름이 쓰여 있으면, 클래스와 분리해서 재사용할 수 없게 된다!!