JAVA/DesignPattern

Design Pattern 디자인패턴 Prototype Pattern 프로토타입 패턴

호두밥 2021. 12. 15. 20:10

Prototype Pattern 프로토타입 패턴

객체를 복사해야 하는 경우에 사용되는 디자인 패턴입니다. 

예를 들어 DB 작업이 많은데, 객체를 저장해야 한다고 하면, 프로토타입 패턴을 이용해 객체를 복사(캐싱) 해놓은 뒤, DB가 여유있을 때 (?) 객체를 저장할 수 있도록 하는데 사용됩니다. 

프로토타입 패턴에서 보통 객체를 복사하는 역할을 맡은 Interface는 clone 메소드 하나만 가집니다.

프로토타입 패턴의 사용

  • 객체의 생성 방법이 시스템과 독립적이어야 하는 경우 ( 클래스 상속 구조와 팩토리(객체 생성 패턴) 구조가 동일한 것을 피하기 위해서)
  • 객체의 인스턴스 생성/변형이 런타임에서 일어나야 하는 경우 ( 객체가 몇가지 상태 표현을 갖는 경우 매번 적절한 상태로 인스턴스를 수동으로 변화시키는 것보다 해당 상태의 프로토타입을 이용해 객체를 복제하는 것이 편리할 수 있습니다.)

프로토타입 패턴의 장단점

장점

  • 미리 만들어진 프로토타입을 이용하여 반복적인 객체 초기화 작업을 줄일 수 있습니다. 
  • 복잡한 구조나 변수를 가진 객체를 좀더 편리하게 생성할 수 있습니다.
  • 서브 클래스를 줄일 수 있습니다.

단점

  •  실제 객체 클래스는 고객에게는 감춰지게 됩니다. (고객은 프로토타입을 통해서 객체에 접근합니다.)
  • 서브클래스마다 clone 메소드를 구현해야 할 수 있습니다.  

 

프로토타입 패턴 구현

복사 메소드를 사용하기 위해 Cloneable를 implements 했습니다. cloneable은 얇은 복사를 가능하게 해주는 기능힙니다.

* 얕은 복사 : 기본타입이면 실제 값이 , 참조타입이면 객체의 번지(주소값)이 복사됨.

* https://mantaray.tistory.com/26#clone()

 

abstract class Shape implements Cloneable {

    private String name;

    public Shape(String name) {
        this.name = name;
    }

    public Shape(Shape shape) {
        super();
        this.name = shape.name;
    }

    public String getName() {
        return name;
    }

    @Override
    public Object clone() {
        try {
            return (Shape) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}
public class Circle extends Shape {

    public Circle() {
        super("Circle");
    }

    public Circle(Circle shape) {
        super(shape);
    }
}
public class Triangle extends Shape{

    public Triangle() {
        super("Triangle");
    }

    public Triangle(Triangle shape) {
        super(shape);
    }
}
public class Prototype {
	
 	private static Map<Integer, Shape> shapeMap = new HashMap<>();

    public static Shape getShape(Integer id) {
        return (Shape) shapeMap.get(id).clone();
    }

    public static void setShape(Integer id, Shape shape) {
        shapeMap.put(id, shape);
    }

}
public class Main {
	
 public static void main(String[] args) {

        prototype prototype = new prototype();

        Shape orgin1 = new Triangle();
        Shape orgin2 = new Circle();
        Shape orgin3 = new Triangle();

        prototype.setShape(1, orgin1);
        prototype.setShape(2, orgin2);
        prototype.setShape(3, orgin3);

        Shape clone1 = prototype.getShape(1);
        System.out.println( "orgin1 : hashCode="+orgin1.toString()
                + ", name="+ orgin1.getName()
                + ", name hashCode="+orgin1.getName().hashCode());
        System.out.println( "clone1 : hashCode="+clone1.toString()
                + ", name="+ clone1.getName()
                + ", name hashCode="+clone1.getName().hashCode());

        Shape clone2 = prototype.getShape(2);
        System.out.println( "orgin2 : hashCode=" +orgin2.toString()
                + ", name="+ orgin2.getName()
                + ", name hashCode="+orgin2.getName().hashCode());
        System.out.println("clone2 : hashCode=" +clone2.toString()
                + ", name="+ clone2.getName()
                + ", name hashCode="+clone2.getName().hashCode());

        Shape clone3 = prototype.getShape(3);
        System.out.println( "orgin3 : hashCode=" +orgin3.toString()
                + ", name="+ orgin3.getName()
                + ", name hashCode="+orgin3.getName().hashCode());

        System.out.println("clone3 : hashCode=" +clone3.toString()
                + ", name="+ clone3.getName()
                + ", name hashCode="+clone3.getName().hashCode());
    }

}

객체의 주소값은 다르지만 데이터의 주소값은 같은 객체가 복사됬음을 확인할 수 있습니다. 

orgin1 : hashCode=javatest.designPattern.prototype.Triangle@71be98f5, name=Triangle, name hashCode=1562406440
clone1 : hashCode=javatest.designPattern.prototype.Triangle@6fadae5d, name=Triangle, name hashCode=1562406440

orgin2 : hashCode=javatest.designPattern.prototype.Circle@17f6480, name=Circle, name hashCode=2018617584
clone2 : hashCode=javatest.designPattern.prototype.Circle@2d6e8792, name=Circle, name hashCode=2018617584

orgin3 : hashCode=javatest.designPattern.prototype.Triangle@2812cbfa, name=Triangle, name hashCode=1562406440
clone3 : hashCode=javatest.designPattern.prototype.Triangle@2acf57e3, name=Triangle, name hashCode=1562406440

참조