Singleton과 Prototpye 리포지토리
GoF 디자인 패턴 중, 생성 패턴에 속하는 ProtoType 패턴은 코드를 클래스들에 의존시키지 않고 기존 객체들을 복사할 수 있도록 하는 패턴입니다.
객체가 있고, 그 객체의 정확한 복사본을 만들고 싶을 경우, 일반적인 방식에서는 같은 클래스의 새 객채를 생성한 다음 원본 객체의 모든 필드를 새 객체로 복사해야 합니다. 하지만 이런 경우, 몇 가지 위험성과 불편한 점이 있습니다.
1. 원본 객체의 필드 중 일부는 private으로 선언되어 있어, 외부에서 볼 수 없다.
2. 해당 원본 객체의 클래스 소스코드를 알아야 할 필요가 있다.
프로토타입 패턴은 실제로 복제되는 객체들에 복제 프로세스를 위임합니다. 복제를 지원하는 객체를 프로토타입이라고 하며, 이 객체에는 자신의 복제본을 내부에서 만들어 반환하는 clone 메소드가 반드시 존재해야 합니다. 수십 개의 필드와 수백 개의 설정들이 존재하는 경우, 유용한 방법이 될 수 있습니다.
자주 사용하는 프로토타입들에 쉽게 접근하는 방법을 제공하려면, Prototype Registry를 사용할 수 있습니다. 이 레지스트리는 복사될 준비가 된 미리 만들어진 객체의 집합을 저장합니다.
문제
ProtoType 레지스트리를 만들고, 객체를 PrototypeRegistry에 등록한 다음 클래스의 이름으로 해당 클래스 인스턴스 객체의 복사본을 반환받을 수 있도록 구현하세요. 조건은 아래와 같습니다:
1. ProtoTypeRegistry 객체는 Singleton 이어야 합니다.
2. CreationType 이라는 이름의 Annotation을 만들고, type 속성에 ProtoType 값이 저장된 클래스의 객체를 등록하고, 등록된 객체를 반환 받을 경우 그 객체는 해당 클래스 인스턴스의 복제본이어야 합니다.
3. CreationType 이라는 이름의 Annotation을 만들고, type 속성에 Singleton 값이 저장된 클래스의 객체를 등록하고, 등록된 객체를 반환 받을 경우 그 객체는 전체 응용 프로그램에서 유일한 객체(Singleton)이어야 합니다.
코드
ObjectType.java (Enum)
public enum ObjectType {
Singleton,
ProtoType;
}
CreationType.java (Annotation)
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CreationType {
ObjectType type() default ObjectType.ProtoType;
}
DataBean.java (Interface)
public interface DataBean {
DataBean clone();
}
Book.java (Data class) -> Book 클래스는 Prototype 객체로 작동하며, clone() 메소드를 통해 복제됨.
@CreationType(type=ObjectType.ProtoType)
public class Book implements DataBean {
private int no;
private String title;
private String subTitle;
private String author;
private String image;
private int price;
private String description;
public Book() {}
public Book(int no, String title, String subTitle, String author, String image, int price, String description) {
this.no = no;
this.title = title;
this.subTitle = subTitle;
this.author = author;
this.image = image;
this.price = price;
this.description = description;
}
public Book no(int no) {
this.no = no;
return this;
}
public Book title(String title) {
this.title = title;
return this;
}
public Book subTitle(String subTitle) {
this.subTitle = subTitle;
return this;
}
public int getNo() {
return this.no;
}
public String getTitle() {
return this.title;
}
public String getSubTitle() {
return this.subTitle;
}
public String getAuthor() {
return this.author;
}
public String getImage() {
return this.image;
}
public String getPrice() {
return String.format("%,d", this.price);
}
public String getDescription() {
return this.description;
}
// @Override
// public String toString() {
// return this.no + ", " + this.title + "," + this.author + ", " + this.getPrice();
// }
public Book clone() {
return new Book(this.no, this.title, this.subTitle, this.author, this.image, this.price, this.description);
}
}
Configurator.java (Data class) -> Configurator 클래스는 Singleton으로 설계되었으며, clone() 메소드는 지원하지 않음을 강조함.
import java.nio.channels.UnsupportedAddressTypeException;
@CreationType(type=ObjectType.Singleton)
public class Configurator implements DataBean {
private String databaseConnectionString;
private String filelocationString;
public String getDatabaseConnectionString() {
return this.databaseConnectionString;
}
public String getFileLocationString() {
return this.filelocationString;
}
public void setDatabaseConnectionString(String value) {
this.databaseConnectionString = value;
}
public void setFilelocationString(String value) {
this.filelocationString = value;
}
public DataBean clone() {
throw new UnsupportedAddressTypeException();
}
}
ObjectRepository.java -> 객체를 어떻게 저장하고, Singleton과 Prototype을 구분하여 return 하는지 설명함.
import java.util.Map;
import java.util.HashMap;
public class ObjectRepository {
private static Map<String, DataBean> repository = new HashMap<>();
public static void register(DataBean bean) {
String className = bean.getClass().getName();
repository.putIfAbsent(className, bean);
}
public static DataBean get(String key) throws IllegalArgumentException {
DataBean b = repository.get(key);
if (b == null) {
throw new IllegalArgumentException("No instence");
}
else {
CreationType annotation = (CreationType)b.getClass().getAnnotations()[0];
if (annotation.type() == ObjectType.Singleton) {
return b;
}
else if (annotation.type() == ObjectType.ProtoType) {
return b.clone();
}
return null;
}
}
}
Test.java
public class Test {
public static void main(String[] args) {
try {
Book book = new Book();
Configurator conf = new Configurator();
ObjectRepository.register(book);
ObjectRepository.register(conf);
System.out.println(ObjectRepository.get("Book"));
System.out.println(ObjectRepository.get("Book"));
System.out.println(ObjectRepository.get("Book"));
System.out.println(ObjectRepository.get("Configurator"));
System.out.println(ObjectRepository.get("Configurator"));
}
catch (IllegalArgumentException e) {}
}
}
실행 결과
- Book 객체는 Prototype 이므로, ObjectRepository.get("Book")을 호출할 때마다 새로운 instance가 반환돼서, 메모리 주소가 다르게 나타난다.
- Configurator 객체는 Singleton이므로, ObjectRepository.get("Configurator")을 호출할 때마다 같은 instance가 반환돼서, 메모리 주소가 동일하게 나타난다.
Book@24273305
Book@33e5ccce
Book@5a42bbf4
Configurator@270421f5
Configurator@270421f5
요약
1. ObjectType.java : 생성 유형 정의.
2. CreationType.java : 객체 생성 방식을 결정하는 annotation.
3. DataBean.java : 복제 기능을 정의하는 Interface.
4. Book.java : Prototype 객체 예시
5. Configurator.java : Singleton 객체 예시
6. ObjectRepository.java : 객체 저장소 관리
7. 테스트
2024.09.02 - [Java] - [Java] 14. Collections Framework
[Java] 14. Collections Framework
Chapter 1: Collection FrameworkCollection 개요Java Collections FrameworkCollection 클래스의 저장 구조Java Collections Framework 구성Collection 인터페이스Collection 인터페이스의 주요 메소드 Chapter 2: Iterator, Comparable, Compa
lightningtech.tistory.com
출처: https://github.com/gikpreet/class-programming_with_java/tree/master
GitHub - gikpreet/class-programming_with_java
Contribute to gikpreet/class-programming_with_java development by creating an account on GitHub.
github.com
'Java > Java 연습 문제' 카테고리의 다른 글
[Java 연습문제] Iterable과 Comparable * - Book 예제 (3) | 2024.09.08 |
---|---|
[Java 연습 문제] 학생 관리 시스템 * (0) | 2024.09.01 |
[Java 연습 문제] String Sort (with Bubble Sort) (0) | 2024.09.01 |
[Java 연습 문제] 상속을 사용하여 인터페이스 구현 (0) | 2024.08.31 |
[Java 연습 문제] 텍스트 파일의 소문자 복사본 생성 (0) | 2024.08.30 |