---
description: >-
  https://app.gitbook.com/@javascriptuse/s/advanced/design-pattern-trong-javascript
---

# Decorator Pattern (ok)

Decorator pattern được sử dụng để mở rộng chức năng của một object mà không làm thay đổi class hiện tại hay hàm tạo. Pattern này có thể được sử dụng để thêm feature mới vào object.

Một ví dụ đơn giản của pattern này:

```
function Car(name) {
  this.name = name;
  // Default values
  this.color = 'White';
}
// Creating a new Object to decorate
const tesla = new Car('Tesla Model 3');
// Decorating the object with new functionality
tesla.setColor = function(color) {
  this.color = color;
}
tesla.setPrice = function(price) {
  this.price = price;
}
tesla.setColor('black');
tesla.setPrice(49000);
// Prints black
console.log(tesla.color);
```

Một ví dụ thực tế khác:

Giả sử giá của xe phụ thuộc vào số tính năng nó có. Nếu không sử dụng decorator pattern, chúng ta sẽ phải tạo nhiều class khác nhau cho tượng trưng cho mỗi loại xe, mỗi class lại định nghĩa một cost method để tính giá trị:

```
class Car() {
}

class CarWithAC() {
}

class CarWithAutoTransmission {
}

class CarWithPowerLocks {
}

class CarWithACandPowerLocks {
}
```

Nhưng với decorator pattern, chúng ta chỉ cần tạo một base class `Car` và tính toán giá dựa vào decorator function. Ví dụ:

```
class Car {
  constructor() {
    // Default Cost
    this.cost = function() {
      return 20000;
    }
  }
}
// Decorator function
function carWithAC(car) {
  car.hasAC = true;
  const prevCost = car.cost();
  car.cost = function() {
    return prevCost + 500;
  }
}
// Decorator function
function carWithAutoTransmission(car) {
  car.hasAutoTransmission = true;
  const prevCost = car.cost();
  car.cost = function() {
    return prevCost + 2000;
  }
}
// Decorator function
function carWithPowerLocks(car) {
  car.hasPowerLocks = true;
  const prevCost = car.cost();
  car.cost = function() {
    return prevCost + 500;
  }
}
const car = new Car();
// Prints 20000
console.log(car.cost());
carWithAC(car);
carWithAutoTransmission(car);
carWithPowerLocks(car);
// Calculating total cost of the car
// Prints 23000
console.log(car.cost());
```

Class `Car` để khởi tạo các object, sau đó được truyền vào decorator function để override hàm `cost` tính giá mới và thêm các thuộc tính xác định tính năng được thêm vào cho `car` instance. Khi sử dụng:

```
const car = new Car();

// Prints 20000
console.log(car.cost());
carWithAC(car);
carWithAutoTransmission(car);
carWithPowerLocks(car);

// Calculating total cost of the car
// Prints 23000
console.log(car.cost());
```

### Kết luận <a href="#ket-luan-11" id="ket-luan-11"></a>

Chúng ta đã tìm hiểu qua một vài design pattern sử dụng trong JavaScript, còn nhiều pattern khác có thể áp dụng được nhưng tôi không đề cập trong bài viết. Tuy nhiên thì việc lạm dụng quá nhiều design pattern cũng là không nên, hãy cân nhắc trước khi áp dụng để tìm được phương án phù hợp nhất. Hi vọng bài viết sẽ giúp ích cho các bạn.
