데코레이터란 무엇인가? 디자인 패턴으로써의 데코레이터의 의미와 typescript에서의 데코레이터 사용법을 알아보자.
디자인패턴으로써의 데코레이터
구조 패턴에 속한다. AOP(Aspect Oriented Programming)의 주요 개념인 흩어진 관심사(Crosscutting Concerns)를 구현하는데 탁월하다. 아래 두 글에서 적절한 비유로 잘 설명해주고 있다.
https://refactoring.guru/ko/design-patterns/decorator
https://gmlwjd9405.github.io/2018/07/09/decorator-pattern.html
위 두 링크의 내용을 간단히 요약해보겠다.
우리가 알림서비스를 개발한다고 가정하자. 유저가 어떤 행동을 했느냐에 따라, SMS 알림을 줄 수도, Facebook 알림을 줄 수도, Slack 알림을 줄 수도 있다. SMS와 Facebook 알림을 줄 수도 있고, Facebook과 Slack 알림을 줄 수도 있고, SMS와 Facebook과 Slack 알림을 모두 줄 수도 있다.
아래와 같이 구현해야 한다면 너무 피곤할 것이다.
const smsNotifier = new SMSNotifier();
const facebookNotifier = new FacebookNotifier();
const slackNotifier = new SlackNotifier();
const smsAndFacebookNotifier = new SMSAndFacebookNotifier();
const smsAndSlackNotifier = new SMSAndSlackNotifier();
const slackAndFacebookNotifier = new SlackAndFacebookNotifier();
const allNotifier = new AllNotifier();
function do() {
doSomething();
// 이 함수는 sms와 slack 알림을 주고 싶으니까 smsAndSlackNotifier를 골라!
const send = smsAndSlackNotifier.send;
send();
}
이렇게 구현한다면 우아하지 않겠는가.
function do() {
doSomething();
// 이 함수는 sms와 slack 알림을 주고 싶으니까 smsNotifier와 slackNotifier를 골라!
const notifier = new SMSDecorator(new SlackDecorator(new Notifier()))
notifier.send();
}
typescript에서 데코레이터라함은 보통 @
를 이용한 문법을 의미한다. 아래처럼 쓰는 것이 제일 우아할 것이다.
@SMSNotify
@SlackNotify
function do() {
doSomething();
}
데코레이터란?
@
를 이용한 문법은 처음 보면 어떻게 동작하는지 가늠이 가지 않아 마법처럼 느껴질 수 있다. 하지만, 이 문법은 typescript, java(Spring Framework AOP), python 등 다양한 언어에서 채택한 문법이다. 아래의 두 python 코드가 완전히 같은 코드라는 사실을 이해해보자.
@decorator
def func(*args):
print('this is decorated func!')
def func(*args):
print('this is decorated func!')
func = decorator(func)
typescript에서의 데코레이터
@
데코레이터는 typescript에서는 완전히 정식으로 채택된 문법은 아니다. 현재 2023년 9월 기준, 이 문법은 tc39 proposal stage3에 머물러있다. 그래서 typescript에서 이 문법을 사용하기 위해서는 tsconfig.json
파일에서 experimentalDecorator
옵션에 true
를 주어야 사용가능하다.
typescript에서 데코레이터를 야무지게 사용한다고 있는 두 가지 라이브러리/프레임워크를 소개한다. 두 사례 모두 흩어진 관심사(Crosscutting Concerns)들을 데코레이터를 활용하여 아주 읽기 쉽고, 생산적이게 제공한다.
TypeORM
NodeJS 진영의 ORM이다. 엔티티 모델을 데코레이터를 활용하여 아주 간단하게 표현할 수 있다.
// 출처: https://typeorm.io/
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column()
firstName: string
@Column()
lastName: string
@Column()
age: number
}
NestJS
NodeJS 진영의 서버 프레임워크이다. 아래 주소는 NestJS에서 공식적으로 제공하는 샘플 중 하나다.
https://github.com/nestjs/nest/tree/master/sample/01-cats-app
Controller, service 등의 코어한 개념과, pipe, guard, middleware 등의 부가적인 기능등을 심플하게 작성할 수 있다.
import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common';
import { Roles } from '../common/decorators/roles.decorator';
import { RolesGuard } from '../common/guards/roles.guard';
import { ParseIntPipe } from '../common/pipes/parse-int.pipe';
import { CatsService } from './cats.service';
import { CreateCatDto } from './dto/create-cat.dto';
import { Cat } from './interfaces/cat.interface';
@UseGuards(RolesGuard)
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Post()
@Roles(['admin'])
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
@Get()
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
@Get(':id')
findOne(
@Param('id', new ParseIntPipe())
id: number,
) {
// get by ID logic
}
}
4종류의 데코레이터
이 섹션은 아래 영상에 더 구체적으로 설명되어 있다.
typescript에서의 데코레이터는 아래의 4종류로 구분 가능하다.
- Class Decorator
- Method Decorator
- Property Decorator
- Parameter Decorator
@Component({
id: 'Hello World',
}) // Class Decorator
export class TestClass {
static elementId: string;
@Prop // Property Decorator
id: number;
@MethodTest // Method Decorator
printId(@Param prefix: string = ""): string { // Parameter Decorator
return prefix + this.id;
}
}
각 Decorator들의 구체적인 구현 방법은 앞서 공유한 유튜브 링크를 참고하자
'개발이야기' 카테고리의 다른 글
Node.js에서 csv 파일 다루기 및 ios-윈도우 간 한글 깨짐 문제 해결 (1) | 2024.01.06 |
---|---|
타입스크립트: ts2322 error 해결을 위한 서브타입 관련 개념 총정리 (1) | 2023.11.26 |
한글의 유니코드 인코딩과, javascript에서 한글 문자열을 다루는 방식 (1) | 2023.10.19 |
HTTP의 역사: 0.9부터 3.0까지 (1) | 2023.09.14 |
Artillery와 함께, 웹 부하테스트 빠르게 익히기 (0) | 2023.08.12 |