데코레이터(Decorator)

2023. 9. 5. 02:27·개발이야기

데코레이터란 무엇인가? 디자인 패턴으로써의 데코레이터의 의미와 typescript에서의 데코레이터 사용법을 알아보자.

디자인패턴으로써의 데코레이터

구조 패턴에 속한다. AOP(Aspect Oriented Programming)의 주요 개념인 흩어진 관심사(Crosscutting Concerns)를 구현하는데 탁월하다. 아래 두 글에서 적절한 비유로 잘 설명해주고 있다.

https://refactoring.guru/ko/design-patterns/decorator
https://gmlwjd9405.github.io/2018/07/09/decorator-pattern.html

위 두 링크의 내용을 간단히 요약해보겠다.

출처: https://refactoring.guru/ko/design-patterns/decorator

우리가 알림서비스를 개발한다고 가정하자. 유저가 어떤 행동을 했느냐에 따라, 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
'개발이야기' 카테고리의 다른 글
  • 타입스크립트: ts2322 error 해결을 위한 서브타입 관련 개념 총정리
  • 한글의 유니코드 인코딩과, javascript에서 한글 문자열을 다루는 방식
  • HTTP의 역사: 0.9부터 3.0까지
  • Artillery와 함께, 웹 부하테스트 빠르게 익히기
준별
준별
  • 준별
    준별개발
    준별
  • 전체
    오늘
    어제
    • 분류 전체보기 (48) N
      • 개발이야기 (12)
        • 토막글 (9)
      • 일상이야기 (6) N
      • 개인 공부 (19) N
      • 생각과 기록 (2)
  • 블로그 메뉴

    • 홈
    • 방명록
    • Github
    • Linkedin
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    맥북세팅
    맥북터미널세팅
    실전압축
    nodejs
    바이브코딩
    k9s
    필수툴
    zsh세팅
    nestjs
    http2.0
    http3.0
    이산구조
    전산기조직
    http1.0
    터미널꾸미기
    데이터베이스
    artillery
    정보보호개론
    zsh-autosuggestion
    http1.1
    데스크셋업
    터미널세팅
    powerlevel10k
    http pipelining
    맥북
    클램쉘
    맥북초기세팅
    조합형
    persistent connection
    Zsh
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
준별
데코레이터(Decorator)
상단으로

티스토리툴바