Java/Java 연습 문제

[Java 연습문제] Singleton과 Prototype 리포지토리 *

Joo.v7 2024. 9. 8. 13:34

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