"JavaScript Design Pattern" 포스팅은 ChatGPT에게 "Essential design patterns for JavaScript developers to learn"로 질문한 뒤 나온 내용에 대해 정리하는 포스팅입니다.
1. 데코레이터 패턴(Decorator Pattern)
데코레이터 패턴은 개발자가 객체를 데코레이터 클래스의 객체로 감싸서 런타임에 새로운 기능을 동적으로 추가할 수 있도록 하는 구조 패턴이다.
데코레이터 패턴을 사용하면 개발자는 객체의 원래 구현을 변경하지 않고도 새로운 동작을 추가하여 객체의 기능을 확장할 수 있다.
데코레이터 패턴은 Component interface, Concrete component, Decorator abstract class, Concrete Decorator의 네 가지 조요 컴포넌트로 구성된다.
- Component: 이 인터페이스는 Concrete Component 및 Concrete Decorator에 의해 구현될 메서드를 정의한다. 이 인터페이스는 추상 클래스 또는 인터페일 수 있다.
- Concrete Component: Component Interface의 기본 구현으로, 데코레이트될 객체이다.
- Decorator: Component Interface를 구현하는 추상 클래스이며 Component Interface의 인스턴스에 대한 참조를 포함한다. Decorator 클래스는 실행 시 Concrete Component에 추가할 수 있는 메서드를 정의한다.
- Concrete Decorator: Decorator 클래스를 확장하고 Concrete Component에 새 기능을 추가하는 클래스다. 또한, Decorator 클래스의 메서드를 호출하여 새로운 기능을 추가할 수 있다.
JavaScript에서 데코레이터 패턴은 다양한 방식으로 구현할 수 있는데, 가장 일반적인 접근 방식은 객체를 인수로 받아 원래 객체를 확장하거나 수정하는 새 객체를 반환하는 고차 함수를 사용하는 것이다.
다음은 JavaScript에서 데코레이터 패턴을 구현한 예이다:
// 간단한 객체 정의
const myObject = {
name: 'John',
age: 30,
sayHello() {
console.log(
`Hello, my name is ${this.name} and I'm ${this.age} years old.`
);
},
};
// 데코레이터 함수 정의
function addJobTitle(obj, title) {
return {
...obj,
jobTitle: title,
sayHello() {
console.log(
`Hello, my name is ${this.name}, I'm ${this.age} years old, and I work as a ${this.jobTitle}.`
);
},
};
}
// 데코레이터를 사용하여 객체에 job title 추가
const decoratedObject = addJobTitle(myObject, 'Developer');
// 장식된 객체에서 sayHello() 메서드를 호출합니다.
decoratedObject.sayHello();
이 예제에는 name, age, 그리고 sayHello() 메서드가 있는 간단한 객체가 있다.
그리고 obj와 title을 가져와 객체에 jobTitle 속성과, sayHello() 메서드를 인사말에 job title을 추가하는 수정된 sayHello() 메서드로 수정하여 원래 객체를 확장한 새 객체를 반환하는 addJobTitle Decorator 함수를 정의한다.
그런 다음, 데코레이터를 사용하여 myObject에 job title을 추가하고 decoratedObject 변수에 저장한다.
데코레이터 패턴은 기존 코드를 변경하지 않고 기존 객체에 새로운 기능이나 동작을 추가해야 할 때 유용하다.
객체와 데코레이터의 관심사를 분리할 수 있으므로 코드를 더 쉽게 유지보수하고 확장할 수 있다.
복잡하고 유연한 시스템을 만들기 위해 팩토리 패턴이나 어댑터 패턴과 같은 다른 디자인 패턴과 함께 사용하는 경우가 많다.
2. Decorator Pattern 연습 코드
ChatGPT에게 "Give me a challenge to practice the Decorator Pattern in JavaScript."라고 질문한 뒤 나온 문제와 그에 대한 답이다.
스켈레톤 코드는 다음과 같다.
class Coffee {
constructor() {
this.description = 'Unknown Coffee';
}
cost() {
return 0;
}
getDescription() {
return this.description;
}
}
class Decorator extends Coffee {
constructor(coffee) {
super();
this.coffee = coffee;
}
cost() {
return this.coffee.cost();
}
getDescription() {
return this.coffee.getDescription();
}
}
class MilkDecorator extends Decorator {
// TODO: Implement the MilkDecorator class
}
class SugarDecorator extends Decorator {
// TODO: Implement the SugarDecorator class
}
class VanillaDecorator extends Decorator {
// TODO: Implement the VanillaDecorator class
}
// Usage
const coffee = new Coffee();
console.log(coffee.getDescription() + ' costs $' + coffee.cost());
const coffeeWithMilkAndSugar = new SugarDecorator(new MilkDecorator(coffee));
console.log(
coffeeWithMilkAndSugar.getDescription() +
' costs $' +
coffeeWithMilkAndSugar.cost()
);
const coffeeWithVanilla = new VanillaDecorator(coffee);
console.log(
coffeeWithVanilla.getDescription() + ' costs $' + coffeeWithVanilla.cost()
);
이를 구현한 코드는 다음과 같다.
class Coffee {
constructor() {
this.description = 'Unknown Coffee';
}
cost() {
return 0;
}
getDescription() {
return this.description;
}
}
class Decorator extends Coffee {
constructor(coffee) {
super();
this.coffee = coffee;
}
cost() {
return this.coffee.cost();
}
getDescription() {
return this.coffee.getDescription();
}
}
class MilkDecorator extends Decorator {
// TODO: Implement the MilkDecorator class
constructor(coffee) {
super(coffee);
this.description = 'Milk';
}
cost() {
return this.coffee.cost() + 0.5;
}
getDescription() {
return this.coffee.getDescription() + ` with ${this.description}`;
}
}
class SugarDecorator extends Decorator {
// TODO: Implement the SugarDecorator class
constructor(coffee) {
super(coffee);
this.description = 'Sugar';
}
cost() {
return this.coffee.cost() + 0.2;
}
getDescription() {
return this.coffee.getDescription() + ` with ${this.description}`;
}
}
class VanillaDecorator extends Decorator {
// TODO: Implement the VanillaDecorator class
constructor(coffee) {
super(coffee);
this.description = 'Vanilla';
}
cost() {
return this.coffee.cost() + 0.7;
}
getDescription() {
return this.coffee.getDescription() + ` with ${this.description}`;
}
}
// Usage
const coffee = new Coffee();
console.log(coffee.getDescription() + ' costs $' + coffee.cost());
const coffeeWithMilkAndSugar = new SugarDecorator(new MilkDecorator(coffee));
console.log(
coffeeWithMilkAndSugar.getDescription() +
' costs $' +
coffeeWithMilkAndSugar.cost()
);
const coffeeWithVanilla = new VanillaDecorator(coffee);
console.log(
coffeeWithVanilla.getDescription() + ' costs $' + coffeeWithVanilla.cost()
);
'Web > JS' 카테고리의 다른 글
[JS] 디자인 패턴(Design Pattern)_퍼사드 패턴(Facade Pattern) (0) | 2023.03.01 |
---|---|
[JS] 디자인 패턴(Design Pattern)_어댑터 패턴(Adapter Pattern) (0) | 2023.02.27 |
[JS] 디자인 패턴(Design Pattern)_옵저버 패턴(Observer Pattern) (0) | 2023.02.25 |
[JS] 디자인 패턴(Design Pattern)_팩토리 패턴(Factory Pattern) (0) | 2023.02.23 |
[JS] 디자인 패턴(Design Pattern)_싱글톤 패턴(Singleton Pattern) (0) | 2023.02.20 |