디자인 패턴

3. Prototype - 패스트캠퍼스 백엔드 부트캠프 3기

gkss2tpt 2025. 2. 10. 15:41

1. Prototype

  • 복사해서 인스턴스를 만든다
    • 종류가 너무 많아 클래스로 정리할 수 없는 경우
      • 취급할 오브젝트 종류가 너무 많아서, 하나하나 다른 클래스로 만들면 소스 파일을 많이 작성해야 하는경우
    • 클래스로부터 인스턴스 생성이 어려운 경우
      • 생성하고 싶은 인스턴스가 복잡한 과정을 거쳐 만들어지는 것으로, 클래스로부터 만들기가 매우 어려운 경우
    • 프레임워크와 생성하는 인스턴스를 분리하고 싶은 경우
      • 인스턴스를 생성하는 프레임워크를 특정 클래스에 의존하지 않게 하고 싶은 경우
    • 왜 복사를 하는가?
      • 생성하는 과정이 어렵고 복잡하고 효율이 안좋아서 복사만하면 그 많은 과정과 자원을 아낄 수 있다.
    • 하나의 객체만 사용하는 것과 복제를 사용하는 것 사이에는 중요한 차이
      • 복제본을 만들면, 원본 객체와 복제본이 각각 독립적인 상태를 가질 수 있다.
    • 하나의 객체만 사용하는 경우 : 하나의 객체를 여러 군데에서 공유해서 사용한다고 가정하면, 이 객체의 상태가 공유됩니다. 즉, 객체의 상태가 하나의 곳에서 변경되면, 그 객체를 사용하는 다른 모든 곳에서 상태 변화가 영향을 미치게 됩니다. 이 방식은 상태 변경을 중앙에서 제어할 수 있긴 하지만, 복잡한 시스템에서는 예기치 않은 부작용을 일으킬 수 있습니다.
    • 복제된 객체를 사용하는 경우 : 프로토타입 패턴을 사용하면, 원본 객체를 복제하여 여러 개의 객체를 만들 수 있고, 이 복제된 객체들은 각각 독립적인 상태를 가질 수 있습니다. 즉, 하나의 객체를 복제하고, 각 복제본이 별도로 변경될 수 있기 때문에, 독립적인 작업을 각 객체가 수행할 수 있습니다.
  • 예제
  • interface Product
package design.prototype.framework;

public interface Product extends Cloneable{
    public abstract void use(String s);     // 사용하기 위한 메서드
    public abstract Product createCopy();   // 인스턴스를 복제하기 위한 메서드
}
  • class Manager
package design.prototype.framework;

import java.util.HashMap;
import java.util.Map;

public class Manager {
    private Map<String, Product> showcase = new HashMap<>();

    // Product를 구현한 클래스를 매개 변수로 받을 수 있다.
    public void register(String name, Product prototype) {
        // key(strong message) value(upen)
        // key(warning box) value(mbox)
        // key(slash box) value(sbox)
        showcase.put(name, prototype);
    }

    public Product create(String prototypeName) {
        // Product p 에 upen, mbox, sbox를 대입
        Product p = showcase.get(prototypeName);
        // 복제본 반환
        return p.createCopy();
    }
}
  • class MessageBox
package design.prototype;

import design.prototype.framework.Product;

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(decochar);
        }
        System.out.println();
    }

    @Override
    public Product createCopy() {
        Product p = null;
        try{
            p = (Product)clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}
  • class UnderlinePen
package design.prototype;

import design.prototype.framework.Product;

public class UnderlinePen implements Product {
    private char ulchar;

    public UnderlinePen(char ulchar){
        this.ulchar = 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() {
        Product p = null;
        try{
            p = (Product)clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return p;
    }
}
  • Main
package design.prototype;

import design.prototype.framework.Manager;
import design.prototype.framework.Product;

public class Main {
    public static void main(String[] args) {
        // 준비
        Manager manager = new Manager();

        // interface Product를 구현한 하위 클래스들
        UnderlinePen upen = new UnderlinePen('-');
        MessageBox mbox = new MessageBox('*');
        MessageBox sbox = new MessageBox('/');

        upen.use("hello");

        // 등록
        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.");
        p1.use("hell");

        Product p2 = manager.create("warning box");
        p2.use("Hello, world.");

        Product p3 = manager.create("slash box");
        p3.use("Hello, world.");
    }
}