본문 바로가기
반응형
Programming/Javascript

자바스크립트(Javascript) 디자인패턴 - 데코레이터 패턴(decorator pattern)(

by JAMINS 2020. 6. 2.

데코레이터 패턴(Decorator Pattern)은 런타임에 필요한 기능을 객체에 동적으로 추가할 수 있는 디자인패턴 중 하나이다. 기대되는 행위를 사용자화하거나 설정할 수 있다. 평범한 객체로 시작하다가 동적으로 사용 가능한 데코레이터들 후보 중에서 원하는 것을 골라 객체에 기능을 추가해 나갈 수 있다. 바로 예시를 들어보자.

예시

물건을 파는 기능을 구현한다고 해보자. Sale 객체를 정의했는데 이는 판매건을 의미한다. 판매할 때 당연히 가격이 존재하며 이는 여러 국가에서 판매한다고 가정했을때, 지역마다 정책이 달라질 것이다. 이럴 때 계산하는 방식을 다르게하는 기능을 동적으로 추가할 수 있다. 이를 장식한다고 표현한다.

var sale = new Sale(100);
sale = sale.decorate('tax');     // 세금 추가
sale = sale.decorate('money');   // 통화 형식 지정
sale.getPrice();   // "$110.22"

자바스크립트로 구현

모든 데코레이터(장식자) 객체에 특정 메서드를 포함하여 메서드를 덮어쓰게 만드는 두 가지 방법을 자바스크립트로 구현해보자. 각 데코레이터는 이전의 객체에서 기능이 추가된 객체를 상속한다.

구현1

// 1. 생성자, 프로토타입 메서드
function Sale(price) {
    this.price = price || 100;
}

Sale.prototype.getPrice = function() {
    return this.price;
}


// 2. 장식자 객체들을 클래스 프로퍼티로 구현
Sale.decorators = {};
Sale.decorators.tax = {
    getPrice: function() {
        var price = this.uber.getPrice();
        price = ...
        return price;
    }
};

Sale.decorators.money = {
    getPrice: function() {
        return "$" + this.uber.getPrice().toFixed(2);
    }
}


// 3. decorate() 구현
Sale.prototype.decorate = function(decorator) {
    var F = function() {};

    // decorator의 재정의된 함수를 불러오기 위함
    var overrides = this.constructor.decorators[decorate];
    var newObj;

    F.prototype = this;
    newObj = new F();
    newObj.uber = F.prototype;

    // overrides의 프로퍼티를 newObj에 복사하고 리턴
    for (var i in overrides) {
        if (overrides.hasOwnProperty(i)) {
            newObj[i] = overrides[i];
        }
    }

    return newObj;
};

구현2 - 목록을 사용

상속을 사용하지 않고 목록을 사용할 수 있다. 이전 메서드의 결과를 다음 메서드에 매개변수로 전달한다. 장식 취소나 제거가 쉽다는 장점이 있다.

function Sale(price) {
    this.price = price || 100;

    // 데코레이터들의 목록을 관리할 배열
    this.decorators_list = [];
}


// 2. Sale 클래스 프로퍼티로 데코레이터 선언
Sale.decorators = {};
Sale.decorators.money = {
    getPrice: function(price) {
        return "$" + price.toFixed(2);
    }
};
...

// 3. decorate 메서드 정의. 목록에 추가하는 역할
Sale.prototype.decorate = function(decorator) {
    this.decorators_list.push(decorator);
}

// 4. Sale의 getPrice 메서드를 정의
Sale.prototype.getPrice = function() {
    var price = this.price,
        i,
        max = this.decorators_list.length,
        name;

    // decorator의 목록을 검사해서 price를 가져온다
    for (i = 0; i < max; i++) {
        name = this.decorators_list[i];
        price = Sale.decorators[name].getPrice(price);
    }

    return price;
}

참고

  • 자바스크립트 디자인패턴 Book

댓글