본문 바로가기

생성 디자인 패턴 - 프로토타입 본문

OOP 디자인 패턴/생성패턴

생성 디자인 패턴 - 프로토타입

개발자로 거듭나기 2023. 5. 19. 09:38
반응형

프로토타입 패턴 (Prototype)

  • clone 이라는 이름으로도 불립니다.
  • 프로토타입은 코드를 그들의 클래스들에 의존시키지 않고 기존 객체들을 복사할 수 있도록 하는 생성 디자인 패턴입니다.
  • 복제를 지원하는 객체를 프로토 타입 이라고 합니다. 당신의 객체들에 수십 개의 필드와 수백 개의 가능한 설정들이 있는 경우 이를 복제하는 것이 서브클래싱의 대안이 될 수 있습니다.
  • 프로토타입 패턴은 실제로 복제되는 객체들에 복제 프로세스를 위임합니다.
  • 프로토타입은 객체들(복잡한 객체 포함)을 그의 특정 클래스들에 결합하지 않고 복제할 수 있도록 하는 생성 디자인 패턴입니다.

프로토타입 구성요소

  1. Prototype 클래스 : 복제를 당할 객체를 정의합니다. 대부분 단일 clone 메서드로 이루어져 있습니다.
  2. ComponentWithBackReference 클래스 : 프로토타입의 클래스를 참조하는 backReference 객체입니다.
  3. 클라이언트 코드 : 객체를 만들고 clnone() 메서드를 이용해서 얼마든지 복제를 수행합니다.

요약

  • 프로토타입 패턴은 객체를 그들의 객체에서 복사하는 것이 아닌, clone 단일메서드를 갖고있는 프로토타입 클래스를 선언하라고 제안합니다.
  • clone 메서드는 객체의 멤버변수, 메서드 들을 복사해서 똑같은 복제본을 생성하는 기능입니다.
  • 아래의 클래스들의 객체들을 복사하는 코드는 얕은복사를 수행해서 그 껍데기는 복제가 되었지만 안의 부분에 만약 객체안의 객체가 있는 형식이라면 그 연결은 끊어지지 않은 상태입니다.
  • 따라서 상황에 맞게 깊은복사를 하는 코드를 clone 메서드를 구현해볼 수 있겠습니다.

BackReference

  • 객체 간에 상호 참조가 있는 경우 사용됩니다.
  • A 객체가 B 객체를 참조하고, B 객체가 다시 A 객체를 참조하는 경우
  • 여기서는 Prototype에서 ComponentWithBackReference를 참조하고 ComponentWithBackReference에서는 다시 Prototype객체를 참조하고 있어서 BackReference 관계가 있습니다.
console.log(p1.circularReference.prototype.circularReference.prototype.circularReference.prototype.circularReference.prototype)
반응형

코드

class Prototype {
    public primitive: any;
    public component: object;
    public circularReference: ComponentWithBackReference;

    public clone(): this {
                // 이 순간 원시 값이 복사됩니다.
        const clone = Object.create(this);

                // 컴포넌트를 복사합니다. 아래의 코드는 얕은복사죠?
        clone.component = Object.create(this.component);

                // 클래스 객체를 담고있는 circularReference를 복사합니다.
                // 이것 역시 얕은복사를 수행합니다.
        clone.circularReference = {
            ...this.circularReference,
            prototype: { ...this },
        };

                // 최종적으로 복사된 객체를 return 합니다.
        return clone;
    }
}

class ComponentWithBackReference {
    public prototype;

    constructor(prototype: Prototype) {
        this.prototype = prototype;
    }
}

function clientCode() {
    const p1 = new Prototype();
    p1.primitive = 1;
    p1.component = [1, 2, 3, 4, 5];
    p1.circularReference = new ComponentWithBackReference(p1);

    const p2 = p1.clone();
    if (p1.primitive === p2.primitive) {
        console.log('원시값이 복제되었습니다.');
    } else {
        console.log('원시값이 복제되지 않았습니다.');
    }
        // 객체를 비교했을 때, 같으면 같은곳을 바라보기 때문에 복제된게 아니겠죠?
    if (p1.component === p2.component) {
        console.log('객체타입의 변수가 복제되지 않았습니다.');
    } else {
        console.log('객체타입의 변수가 복제되었습니다.');
    }

    if (p1.circularReference === p2.circularReference) {
        console.log('클래스 타입의 변수가 복제되지 않았습니다.');
    } else {
        console.log('클래스 타입의 변수가 복제되었습니다.');
    }

    if (p1.circularReference.prototype === p2.circularReference.prototype) {
        console.log('클래스 내부의 prototype 변수가 복제되지 않았습니다.');
    } else {
        console.log('클래스 내부의 prototype 변수가 복제되었습니다.');
    }
}

clientCode();

결과

출처

https://refactoring.guru/ko/design-patterns/prototype

반응형
Comments