본문 바로가기
Design Pattern/Creational Design

[Design Pattern] (Creational) 프로토타입 패턴(Prototype Pattern)

by song.ift 2023. 3. 26.

디자인 패턴 유형

  • Creation Design Pattern
    • 객체의 생성에 관련된 패턴
    • 객체의 생성 로직을 숨김으로써 유연성을 향상시킨다.
  • Strutural Design Pattern
    • 클래스와 객체의 구성에 관련된 패턴
  • Behavioral Design Pattern
    • 객체와 객체 간의 통신에 관련된 패턴

 

[Creational Design Pattern] 프로토타입 패턴(Prototype Pattern)

prototype 디자인 패턴은 다른 객체의 프로토 타입 역할을하는 객체를 만드는 프로토 타입 상속을 기반으로한다고 생각할 수 있다.프로토타입 패턴은 객체를 효율적으로 생성하는 방식으로  객체의 템플릿을 기반으로 새로운 객체를 만들 수 있다.

프로토타입 개체 자체는 생성자가 만드는 각 개체의 청사진으로 효과적으로 사용되며, 전달된 원본 객체의 복제본(얕은 복제본)이다. 사용된 생성자 함수의 프로토 타입에 name과 같은 속성이 들어 있으면 (코드 샘플의 아래쪽에서와 같이) 동일한 생성자가 만든 각 객체에도 동일한 속성이 있다.

 

장점

  • 생성된 원본 객체를 복사해서 사용하기 때문에, 객체를 생성하는 비용이 클 때 그리고 성능이 중요한 상황에서 사용할 수 있다.
    • 광범위한 데이터베이스 작업을 수행하여 애플리케이션의 다른 부분에 사용되는 객체를 만드는 것이다. 다른 프로세스가 이 객체를 사용해야 할 경우, 데이터베이스 작업을 수행하는 대신 이전에 만든 객체를 복제하는 것이 좋다.
  • 프로토타입 패턴은 다른 언어의 기능을 모방하지 않고, JavaScript가 제공해야하는 프로토타입의 강점과 함께 작업한다는 것이다. 다른 디자인 패턴의 경우 항상 그렇지는 않습니다.
    • 프로토타입 패턴은 상속을 기반으로 하지만, JavaScript는 Object의 create() 메소드를 활용하여 손쉽게 구현이 가능하다

즉 프로토타입 패턴은 상속을 구현하는 쉬운 방법 일뿐만 아니라 성능을 향상시킬수도 있으며, 객체에서 함수를 정의 할 때 참조로 작성된다. (모든 하위 객체는 동일한 함수를 가리킨다) 

 

 

ex)

Object.create는 지정된 프로토 타입을 가지며 선택적으로 지정된 속성 (예 : Object.create (prototype, optionalDescriptorObjects))을 포함하는 객체를 만든다.

 
var myCar = {
  name: "Ford Escort",

  drive: function () {
    console.log( "Weeee. I'm driving!" );
  },

  panic: function () {
    console.log( "Wait. How do you stop this thing?" );
  }

};

var yourCar = Object.create( myCar );
console.log( yourCar.name );

 

또한 Object.create를 사용하면 객체가 다른 객체에서 직접 상속받을 수있는 차등 상속과 같은 고급 개념을 쉽게 구현할 수 있다. Object.create를 사용하면 두 번째 제공된 인수를 사용하여 객체 속성을 초기화 할 수 있다.

var vehicle = {
  getModel: function () {
    console.log( "The model of this vehicle is.." + this.model );
  }
};

var car = Object.create(vehicle, {
  "id": {
    value: MY_GLOBAL.nextId(),
    enumerable: true
  },

  "model": {
    value: "Ford",
    enumerable: true
  }
});
class Car {
  constructor (_wheels) {
    this.noOfWheels = _wheels;
  }
  
  start() {
    return `start ${this.noOfWheels}`;
  }
  
  stop() {
    return `stop ${this.noOfWheels}`;
  }
}

const car = new Car(4);

const cloneCar1 = Object.create(car, { owner: { value: 'Mung1' } });
const cloneCar2 = Object.create(car, { owner: { value: 'Mung2' } });

console.log(cloneCar1.__proto__ === car); // true
console.log(cloneCar2.__proto__ === car); // true

cloneCar2.noOfWheels += 10

console.log(cloneCar1.start()) // start 4
console.log(cloneCar1.stop()) // stop 4
console.log(cloneCar1.noOfWheels) // 4
console.log(cloneCar1.owner)  // Mung1

console.log(cloneCar2.noOfWheels) // 14

여기에서 앞서 살펴본 Object.defineProperties 및 Object.defineProperty 메서드에서 사용되는 것과 유사한 구문을 사용하여 개체 리터럴을 사용하여 Object.create의 두 번째 인수에서 속성을 초기화 할 수 있다.

 

Object.create를 직접 사용하지 않고 프로토 타입 패턴을 구현하려는 경우 다음과 같이 패턴을 위에서와 같이 시뮬레이트 할 수 있다.

var vehiclePrototype = {
  init: function ( carModel ) {
    this.model = carModel;
  },
  
  getModel: function () {
    console.log( "The model of this vehicle is.." + this.model);
  }
};


function vehicle( model ) {
  function F() {};
  F.prototype = vehiclePrototype;

  var f = new F();

  f.init( model );
  return f;
}

var car = vehicle( "Ford Escort" );
car.getModel();

이 대안에서는 사용자가 동일한 방식으로 읽기 전용 속성을 정의 할 수 없다 (주의하지 않으면 vehiclePrototype이 변경 될 수 있음).

var beget = (function () {
    function F() {}

    return function ( proto ) {
        F.prototype = proto;
        return new F();
    };
})();

댓글