티스토리 뷰
보통 new 키워드를 사용해서 클래스 이름을 지정하여 인스턴스를 생성한다.
그러나 클래스 이름을 지정하지 않고 인스턴스를 생성할 때도 있다.
다음과 같은 경우에는 클래스로부터가 아닌 인스턴스를 복사해서 새로운 인스턴스를 만든다.
[1]. 종류가 너무 많아 클래스로 정리되지 않는 경우
취급하는 오브젝트의 종류가 너무 많아서 각각을 별도의 클래스로 만들어 다수의 소스 파일로 작성하는 경우
[2]. 클래스로부터 인스턴스 생성이 어려운 경우
생성하고 싶은 인스턴스가 복잡한 작업을 거쳐 만들어지기 때문에 클래스로부터 만들기가 어려운 경우
ex) 그래픽 에디터에서 사용자가 마우스를 조작해서 만든 도형을 나타내는 인스턴스가 있다고 가정해보자.
사용자의 조작으로 인스턴스를 프로그래밍해서 만드는 것은 곤란하다.
사용자의 조작으로 만들어진 인스턴스를 다시 만들고 싶을 경우에는 지금 만든 인스턴스를 일단 저장해두고 만들고 싶은 경우에 그것을 복사한다.
[3]. framework와 생성할 인스턴스를 분리하고 싶은 경우
인스턴스를 생성할 때의 framework를 특정 클래스에 의존하지 않도록 만들고 싶은 경우
이와 같은 경우에는 클래스 이름을 지정해서 인스턴스를 만드는 것이 아니라 이미 ‘모형'이 되는 인스턴스를 등록해 두고, 그 등록된 인스턴스를 복사해서 인스턴스를 생성한다.
프로토타입 패턴
이 패턴은 클래스로부터 인스턴스를 생성하는 것이 아니라 인스턴스로부터 별도의 인스턴스를 만드는 패턴이다.
import prototype.framework.Manager;
import prototype.framework.Product;
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.");
}
}
GitHub - kkoon9/Java-Design-Pattern: Java 언어로 배우는 디자인 패턴 입문 예제 코드
Java 언어로 배우는 디자인 패턴 입문 예제 코드. Contribute to kkoon9/Java-Design-Pattern development by creating an account on GitHub.
github.com
프로토타입 패턴의 핵심 키워드
예제 코드와 동작을 살펴봤으니 이젠 핵심 키워드를 살펴보자.
Prototype(원형)의 역할 - Product
인스턴스를 복사하여 새로운 인스턴스를 만들기 위한 메서드를 결정한다.
ConcretePrototype(구체화 원형)의 역할 - MessageBox, UnderlinePen
인스턴스를 복사해서 새로운 인스턴스를 만드는 메서드를 실제 구현한다.
Clinet(이용자)의 역할 - Manager
인스턴스를 복사하는 메서드를 이용해서 새로운 인스턴스를 만든다.
위에서 설명했던 클래스로부터가 아닌 인스턴스를 복사해서 새로운 인스턴스를 만드는 예시에 대해서 위 예제 코드를 빗대어 정리해보자.
[1]. 종류가 너무 많아 클래스로 정리되지 않는 경우
예제 코드에서는 3개의 모형이 등장했다.
- ‘~’를 사용해서 문자열에 밑줄을 긋는 것
- ‘*’을 사용해서 문자열에 테두리를 긋는 것
- ‘/’을 사용해서 문자열에 테두리를 긋는 것
이렇게 많은 종류의 모형을 만들 수 있다.
그러나 이것을 모두 각각의 클래스로 만들면 클래스의 수가 너무 많아지기 때문에 소스 프로그램을 관리하기 힘들다.
[2]. 클래스로부터 인스턴스 생성이 어려운 경우
위 예제 코드에서는 딱히 없다.
[3]. framework와 생성할 인스턴스를 분리하고 싶은 경우
인스턴스의 복사(clone)를 실행하는 부분을 framework 패키지 내에 설정하고 있다.
Manager 클래스의 create 메서드에는 클래스 이름 대신에 ‘strong message’나 slash box’라는 문자열을 인스턴스 생성을 위한 이름으로 제공하고 있다.
🤔 클래스 이름은 나쁜건가?
소스의 내부에 이용할 클래스의 이름을 쓰는 것이 항상 나쁜 것만은 아니다.
그러나 소스 내부에 이용할 클래스의 이름이 쓰여있으면 그 클래스와 분리해서 재이용할 수 없게 된다.
소스 파일(.java)이 없어도 재사용할 수 있는지가 포인트다.
관련 패턴
- Flyweight 패턴
- Memento 패턴
- Composite 및 Decorator 패턴
- Command 패턴
위에서 사용한 Cloneable 인터페이스를 상속한 Product 인터페이스를 사용하기 전에 Effective Java에 나오는 ‘아이템13 clone 재정의는 주의해서 진행하라’를 읽어보는 것이 좋아 보인다.
clone 메서드와 Cloneable 인터페이스
Java 에서는 인스턴스의 복사를 실행하는 도구로 clone 메서드가 있다.
복사 대상이 되는 클래스는 java.lang.Cloneable 인터페이스를 구현할 필요가 있다.
Cloneable 인터페이스를 구현한 클래스의 인스턴스는 clone 메서드를 호출하면 복사된다.
그리고 clone 메서드의 반환값은 복사해서 만들어진 인스턴스가 된다.
(내부에서 하는 일은 원래의 인스턴스와 같은 크기의 메모리를 확보해서, 그 인스턴스의 필드 내용을 복사하는 것)
Cloneable 인터페이스를 구현하지 않는 클래스의 인스턴스가 clone 메서드를 호출하면 예외가 발생한다.
clone 메서드는 Object 클래스에서 정의되어 있다.
clone 메서드를 사용해서 복사를 한 경우 그 필드에 대한 참조만 복사될 뿐이다.
배열을 예로 들면, 배열에 대한 참조만 복사될 뿐 요소 하나하나가 복사되는 것이 아니다.
이와 같은 필드 대 필드의 복사를 피상적인 복사(shallow copy)라고 한다.
또한 clone은 복사를 할 뿐이며 생성자를 호출하는 것이 아니라는 점에 주의할 필요가 있다.
또한 인스턴스 생성 시에 무엇인가 특수한 초기화를 필요로 하는 클래스에서는 clone 메서드 안에 처리를 기술할 필요가 있다.
'JAVA > 디자인 패턴' 카테고리의 다른 글
컴포지트(Composite) 패턴 (0) | 2022.03.21 |
---|---|
전략(Strategy) 패턴 (0) | 2022.03.21 |
싱글톤(Singleton) 패턴 (0) | 2022.03.11 |
Factory Method 패턴 (0) | 2022.03.11 |
Template Method 패턴 (0) | 2022.03.10 |
- Total
- Today
- Yesterday
- 객체지향
- 코테
- MSA
- 알고리즘
- 디자인패턴
- 클린 아키텍처
- AWS
- Algorithm
- BAEKJOON
- 클린 코드
- 디자인 패턴
- kkoon9
- Spring Boot
- BOJ
- Spring
- programmers
- 백준
- 이팩티브 자바
- 테라폼
- node.js
- Olympiad
- 프로그래머스
- 이펙티브 자바
- JPA
- 정규표현식
- C++
- Kotlin
- kotest
- Java
- Effective Java
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |