Design Pattern, Prototype

2022. 2. 17. 23:40ETC/Design Patterns

반응형

 

Object Creational Pattern

Prototype Pattern

 

-----------------    INDEX     -----------------

 

Prototype Pattern ?

Structure

Sample Code: Java

java.lang.Cloneable

관련 패턴

 

----------------------------------------------

 

 

Specify the kinds of objects to create using a prototypical instance,
and create new objects by copying this prototype.


- GoF Design Patterns

 

 

프로토타입 패턴 원본 인스턴스로 생성할 객체의 유형을 결정하고, 원본을 복제하여 새 객체를 만드는 패턴입니다.

 

 

Prototype

프로토타입의 사전적 의미는 ‘원형'입니다.

객체를 복제하려면 먼저 생성된 원본 객체가 있어야 합니다.

 

복제 대상인 객체가 존재하지 않으면 복제할 수 없으며,

복제 대상이 되는 원본 객체를 원형, 즉 프로토타입이라고 합니다.

 

실생활에서도 실제 제품을 만들기에 앞서 테스트를 위한 샘플 제품을 만드는데 이때, 샘플 제품을 프로토타입이라고 합니다.

프로토타입은 원래의 형태 또는 전형적인 예, 기초 또는 표준입니다.

 

 

Clone

프로토타입패턴도 동일합니다. 원본 객체로 부터 새로운 객체를 생성하는 생성패턴입니다.

프로토타입 패턴은 객체를 새로 생성하지 않고, 기존에 생성된 유사한 객체를 복제합니다.

 

기존 객체를 복제하면 객체를 새로 생성하는 것보다 자원을 절약할 수 있습니다.

또한, 하나의 객체를 구성하는 시간이나 코드를 줄일 수 있으며

하나의 객체를 통해 유산한 객체를 다수의 객체를 간단히 생산할 수도 있습니다.

이를 정리하면 아래와 같습니다.

 

 

Prototype 특징

✔️  new를 통한 생성보다 자원 절약

✔️  유사한 다수 객체 생산 가능

✔️  다수의 복잡한 객체를 처리할 때 유용

✔️  반복적인 초기화 코드를 제거

❌  순환 참조가 있는 복잡한 개체를 복제하는 것은 매우 까다로울 수 있음

 

 

 

Structure

 

GoF Design Patterns - Prototype

 

Prototype

- 스스로를 복제하기 위한 인터페이스를 선언합니다.

ConcretePrototype

- 스스로를 복제하기 위한 작업을 구현합니다.

 

Client

- 프로토타입이 스스로를 복제하게끔 요청해서 새로운 객체를 만듭니다.

 

 

 

Sample Code: Java

Prototype

public abstract class Shape {
    public int x;
    public int y;
    public String color;

    public String getShape() {
        return "position: (" + x + ", " + y + "), color: " + color;
    }

    public abstract Shape clone();

    @Override
    public boolean equals(Object object2) {
        if (!(object2 instanceof Shape)) return false;
        Shape shape2 = (Shape) object2;
        return shape2.x == x && shape2.y == y && Objects.equals(shape2.color, color);
    }
}

 

 

ConcretePrototype

public class Circle extends Shape {
    public int radius;

    public Circle() {}

    public Circle(Circle target) {
        this.radius = target.radius;
    }

    @Override
    public String getShape() {
        return super.getShape() + ", " + radius + "°";
    }

    @Override
    public Shape clone() {
        return new Circle(this);
    }

    @Override
    public boolean equals(Object object2) {
        if (!(object2 instanceof Circle) || !super.equals(object2)) return false;
        Circle shape2 = (Circle) object2;
        return shape2.radius == radius;
    }
}
public class Rectangle extends Shape {
    public int width, height;

    public Rectangle() {}

    public Rectangle(Rectangle target) {
        this.width = target.width;
        this.height = target.height;
    }

    @Override
    public String getShape() {
        return "width: " + width + ", height: " + height;
    }

    @Override
    public Shape clone() {
        return new Rectangle(this);
    }

    @Override
    public boolean equals(Object object2) {
        if (!(object2 instanceof Rectangle) || !super.equals(object2)) return false;
        Rectangle shape2 = (Rectangle) object2;
        return shape2.width == width && shape2.height == height;
    }
}

 

 

Client

public class Client {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.x = 10;
        circle.y = 20;
        circle.radius = 15;
        circle.color = "red";
        Circle clonedCircle = (Circle) circle.clone();

        System.out.println("[circle] " + circle.getShape());
        System.out.println("[clonedCircle] " + clonedCircle .getShape());
        System.out.println("circle equals anotherCircle? " + circle.equals(clonedCircle));

        Rectangle rect = new Rectangle();
        rect.width = 10;
        rect.height = 20;
        rect.color = "blue";
        System.out.println("\n=== Clone Multiple Object ===");
        for (int i = 0; i < 3; i++) {
            Rectangle clonedRect = (Rectangle) rect.clone();
            System.out.println("[clonedRect " + i + "] "+ clonedRect.getShape());
        }
    }
}

 

위의 코드처럼, 미리 설정된 객체를 복제함으로써 아주 간편하게 제작할 수 있습니다.

또한, Rectangle 객체를 여러개 생성할 때에도 쉽게 이루어집니다.

위의 코드를 실행하면 아래와 같은 결과값이 나옵니다.

 

 

Output

[circle] position: (10, 20), color: red, 15°
[clonedCircle] position: (0, 0), color: null, 15°
circle equals anotherCircle? false

=== Clone Multiple Object ===
[clonedRect 0] width: 10, height: 20
[clonedRect 1] width: 10, height: 20
[clonedRect 2] width: 10, height: 20

 

 

 

java.lang.Cloneable

자바에서는 Cloneable 인터페이스를 제공하여 프로토타입 형식을 제작할 수 있습니다.하지만, 실제 인터페이스를 확인해보면 아무런 내용이 담겨있지 않은데요.단순히 해당 객체에 의해 복제될 수 있다는 내용을 담은 maker interface 입니다.

 

자바에서는  java.lang.Object 클래스에 clone() 메서드가 정의되어있습니다. Object 클래스는 기본 클래스이기 때문에 어느 클래스에서도 clone 메소드를 상속할 수 있습니다.

 

간단히 표현하자면 아래와 같습니다.

 

class Prototype implement Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

 

이를 구현한 간단한 예시를 Github에 올려두었으니, 필요하다면 확인해보실 수 있습니다.

 

 

관련 패턴

C- Creational Patterns  |  S - Structural Patterns  |  B - Behavioral Patterns

 

 

C: Abstract Factory

Abstract Factory 클래스는 프로토타입 패턴과 경쟁 관계의 패턴이지만,

프로토타입을 사용하여 이러한 클래스에 메서드를 구성할 수도 있습니다.

 

 

S: Flyweight

객체를 공유하거나 동일한 상태의 객체를 별도로 생성할 때 프로토타입 패턴을 같이 사용할 수 있습니다. 

 

 

S: Composite, Decorator

객체가 동적으로 생성될 때 프로토타입 패턴을 사용할 수 있습니다.

 

이 두 패턴은 프로토타입을 사용하면 많은 이점을 얻을 수 있습니다.

패턴을 적용하면 복잡한 구조를 처음부터 재구성하지 않고 복제할 수 있습니다.

 

 

B: Memento

메멘토 패턴은 객체를 저장하는 역할을 수행합니다.

객체 저장 시 프로토타입 패턴을 같이 응용할 수 있다.

 

 

B: Command

명령을 복제할 때 프로토타입을 사용할 수 있습니다.

 

 

 

 

 

 

그럼 지금까지 Prototype Pattern에 대해 알아보았습니다.

오타나 잘못된 내용이 있다면 댓글로 남겨주세요!

감사합니다 ☺️ 

 

 

 

모든 Design Patterns 모아보기

 

Design Patterns

안녕하세요. GoF 디자인 패턴을 정리하고자 합니다. 디자인 패턴은 일주일 전부터 공부를 시작했는데, 스스로 설명하듯 적는게 익히는데 도움이 클 것같아 정말 오랜만에 시리즈로 포스팅하려

gngsn.tistory.com

 

 

반응형

'ETC > Design Patterns' 카테고리의 다른 글

Design Pattern, Chain of Responsibility  (0) 2022.02.19
Design Pattern, Flyweight  (0) 2022.02.18
Design Pattern, Memento  (0) 2022.02.17
Design Pattern, State  (0) 2022.02.16
Design Pattern, Visitor  (0) 2022.02.13