본문 바로가기
Dart/Study

Dart에서 어노테이션 알아보기: 초보자를 위한 가이드

by Maccrey Coding 2024. 7. 12.
반응형

Dart에서 어노테이션은 코드에 메타데이터를 추가하는 강력한 도구입니다.

마치 책에 책갈피를 달거나 하이라이트를 칠하는 것처럼, 어노테이션은 코드에 추가적인 정보를 제공하여 코드를 더욱 이해하기 쉽고 유지 관리하기 용이하게 만들어줍니다.

이 블로그 게시글에서는 Dart에서 어노테이션의 기본 개념부터 다양한 사용법까지, 초보자도 쉽게 이해할 수 있도록 심층적으로 살펴보겠습니다.

1. 어노테이션이란 무엇일까요?

어노테이션은 클래스, 함수, 변수, 매개변수 등 다양한 코드 요소에 추가할 수 있는 특별한 문자 시퀀스입니다.

어노테이션은 다음과 같은 다양한 목적으로 사용됩니다.

  • 코드 문서화: 어노테이션을 사용하여 코드의 기능, 사용 방법, 제약 조건 등을 명확하게 설명할 수 있습니다. 이는 코드를 이해하고 사용하는 다른 개발자들에게 큰 도움이 됩니다.
  • 코드 구성 및 조직화: 어노테이션을 사용하여 코드를 논리적으로 그룹화하고 분류할 수 있습니다. 이는 코드를 더욱 읽기 쉽고 유지 관리하기 용이하게 만듭니다.
  • 코드 제어 및 자동화: 어노테이션을 사용하여 컴파일러나 다른 도구가 코드를 처리하는 방식을 제어할 수 있습니다. 예를 들어, 테스트 코드를 식별하거나 특정 코드를 최적화하도록 지시하는 데 사용할 수 있습니다.

2. 어노테이션 사용 방법

어노테이션을 사용하려면 다음과 같은 단계를 따릅니다.

  1. 어노테이션 클래스 정의: 어노테이션을 나타내는 클래스를 정의합니다. 이 클래스는 어노테이션의 이름, 매개변수, 기타 속성을 정의합니다.
  2. 코드 요소에 어노테이션 추가: 어노테이션 클래스를 사용하여 코드 요소에 어노테이션을 추가합니다. 어노테이션은 @ 기호로 시작하며, 어노테이션 이름과 괄호 안에 매개변수 값 (있는 경우)을 지정합니다.

예시

// 어노테이션 클래스 정의
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CLASS, ElementType.FUNCTION})
class MyAnnotation {
  final String message;

  const MyAnnotation(this.message);
}

// 코드 요소에 어노테이션 추가
@MyAnnotation(message: "This is an example annotation.")
class MyClass {
  // ...
}
 

설명

  • @Retention(RetentionPolicy.RUNTIME) 어노테이션은 컴파일 후에도 어노테이션 정보가 유지되도록 합니다.
  • @Target({ElementType.CLASS, ElementType.FUNCTION}) 어노테이션은 이 어노테이션이 클래스와 함수에 사용될 수 있음을 나타냅니다.
  • MyAnnotation 클래스는 message이라는 문자열 매개변수를 가진 어노테이션을 정의합니다.
  • @MyAnnotation(message: "This is an example annotation.") 은 MyClass 클래스에 MyAnnotation 어노테이션을 추가하고, message 매개변수에 "This is an example annotation." 값을 지정합니다.

3. 어노테이션 종류

Dart에서 제공하는 기본 어노테이션 종류는 다음과 같습니다.

  • @Retention: 어노테이션 정보가 유지되는 기간을 지정합니다.
  • @Target: 어노테이션을 사용할 수 있는 코드 요소를 지정합니다.
  • @Deprecated: 코드가 더 이상 사용되지 않음을 나타냅니다.
  • @Optional: 어노테이션 매개변수가 선택적임을 나타냅니다.
  • @Default: 어노테이션 매개변수의 기본값을 지정합니다.

이 외에도 다양한 사용자 정의 어노테이션을 만들 수 있습니다.

4. 어노테이션 활용 사례

  • 코드 문서화
/// This class represents a person.
@deprecated('Use `User` class instead.')
class Person {
  /// The person's name.
  final String name;

  /// The person's age.
  final int age;

  Person(this.name, this.age);
}
 

위 코드에서 @deprecated 어노테이션은 Person 클래스가 더 이상 사용되지 않고 User 클래스를 대신 사용해야 한다는 것을 나타냅니다.

또한, 각 속성에 대한 주석은 코드의 기능을 명확하게 설명합니다.

  • 코드 구성 및 조직화
@Todo('Implement this function')
void doSomething() {
  // ...
}
 

위 코드에서 @Todo 어노테이션은 doSomething 함수가 아직 구현되지 않았음을 나타냅니다.

이는 코드를 논리적으로 그룹화하고, 해야 할 작업을 명확하게 파악하는 데 도움이 됩니다.

  • 코드 제어 및 자동화
@Test()
void testMyFunction() {
  // ...
}
 

위 코드에서 @Test 어노테이션은 testMyFunction 함수가 테스트 코드임을 나타냅니다.

이는 테스트 코드를 자동으로 실행하고 코드 품질을 유지 관리하는 데 도움이 됩니다.

5. 실습 문제

다음 문제를 해결해 봅시다.

 

문제

다음 상황을 모델링하기 위해 어노테이션을 사용하여 클래스를 설계하세요.

  • 도서관을 나타내는 클래스를 만듭니다.
  • 각 도서관에는 이름, 위치, 소장 도서 수 속성이 있어야 합니다.
  • 도서관의 이름, 위치, 소장 도서 수를 출력하는 메서드를 작성합니다.
  • 서로 다른 도서관 유형을 나타내는 클래스를 상속하여 만들고, 각 유형별 특징을 나타내는 속성과 메서드를 추가합니다.
  • 예를 들어, 대중 도서관은 정부에서 운영되고, 대출 가능한 도서 수가 제한될 수 있습니다.
  • 학술 도서관은 대학에서 운영되고, 연구 관련 자료가 풍부할 수 있습니다.

해결 팁

  • Library 클래스를 만들어 도서관의 공통 속성과 메서드를 정의합니다.
  • @Retention(RetentionPolicy.RUNTIME) 어노테이션을 사용하여 어노테이션 정보가 런타임까지 유지되도록 합니다.
  • @Target({ElementType.CLASS}) 어노테이션을 사용하여 어노테이션이 클래스에만 사용될 수 있음을 나타냅니다.
  • PublicLibrary 클래스와 AcademicLibrary 클래스를 만들어 Library 클래스를 상속받고, 각 유형별 특징을 나타내는 속성과 메서드를 추가합니다.
  • @override 어노테이션을 사용하여 상속받은 메서드를 재정의합니다.

이 문제를 통해 어노테이션을 사용하여 코드를 설계하고 구성하는 방법을 연습할 수 있습니다.

 

정답

 

다음은 주어진 상황을 모델링하기 위해 어노테이션을 사용하여 설계한 클래스입니다.

import 'package:meta/meta.dart'; // 어노테이션을 사용하기 위해 meta 패키지를 가져옵니다.

@immutable // 클래스가 변경 불가능함을 나타냅니다.
abstract class Library {
  final String name;
  final String location;
  final int bookCount;

  Library({@required this.name, @required this.location, @required this.bookCount});

  void printInfo() {
    print("Name: $name");
    print("Location: $location");
    print("Book Count: $bookCount");
  }
}

// 대중 도서관 클래스
class PublicLibrary extends Library {
  final String 운영단체;
  final int 대출가능도서수;

  PublicLibrary({
    @required String name,
    @required String location,
    @required int bookCount,
    @required this.운영단체,
    @required this.대출가능도서수,
  }) : super(name: name, location: location, bookCount: bookCount);

  @override
  void printInfo() {
    super.printInfo();
    print("운영단체: $운영단체");
    print("대출가능도서수: $대출가능도서수");
  }
}

// 학술 도서관 클래스
class AcademicLibrary extends Library {
  final String 연구자료수;

  AcademicLibrary({
    @required String name,
    @required String location,
    @required int bookCount,
    @required this.연구자료수,
  }) : super(name: name, location: location, bookCount: bookCount);

  @override
  void printInfo() {
    super.printInfo();
    print("연구자료수: $연구자료수");
  }
}
 

설명

  • Library 클래스:
    • @immutable 어노테이션으로 클래스가 변경 불가능함을 명시합니다.
    • name, location, bookCount 속성을 가지고 일반적인 도서관의 정보를 나타냅니다.
    • printInfo 메서드는 도서관 정보를 출력합니다.
  • PublicLibrary 클래스:
    • Library 클래스를 상속받고, 대중 도서관의 특징인 운영다체 대출가능도서수 속성을 추가합니다.
    • printInfo 메서드를 재정의하여 운영단체 대출가능도서수 정보도 출력합니다.
  • AcademicLibrary 클래스:
    • Library 클래스를 상속받고, 학술 도서관의 특징인 연구자료수 속성을 추가합니다.
    • printInfo 메서드를 재정의하여 연구자료수 정보도 출력합니다.

사용 예시

void main() {
  PublicLibrary publicLibrary = PublicLibrary(
    name: "Seoul Public Library",
    location: "Seoul, South Korea",
    bookCount: 100000,
    운영단체: "Seoul Metropolitan Government",
    대출가능도서수: 50000,
  );

  AcademicLibrary academicLibrary = AcademicLibrary(
    name: "KAIST Library",
    location: "Daejeon, South Korea",
    bookCount: 500000,
    연구자료수: 1000000,
  );

  publicLibrary.printInfo();
  academicLibrary.printInfo();
}
 

출력

Name: Seoul Public Library
Location: Seoul, South Korea
Book Count: 100000
운영단체: Seoul Metropolitan Government
대출가능도서수: 50000
Name: KAIST Library
Location: Daejeon, South Korea
Book Count: 500000
연구자료수: 1000000

6. 마무리

이 블로그 게시글에서는 Dart에서 어노테이션의 기본 개념부터 다양한 사용법까지, 초보자도 쉽게 이해할 수 있도록 심층적으로 살펴보았습니다.

어노테이션을 활용하여 코드를 더욱 효과적으로 작성하고 유지 관리할 수 있기를 바랍니다.

더 궁금한 점이나 개선할 부분이 있다면 언제든지 코멘트를 남겨주세요.

 

반응형