본문 바로가기
Dart/Dart Programming language

[고급] Dart 메타프로그래밍/ 리플렉션(Reflection) 기초

by Maccrey Coding 2024. 9. 8.
반응형

 

 

프로그래밍을 하다 보면 프로그램 실행 중에 클래스나 객체의 정보를 동적으로 탐색하거나 조작해야 할 때가 있습니다.

이를 가능하게 해주는 기능이 바로 리플렉션(Reflection)입니다.

이번 글에서는 리플렉션이 무엇인지, 그리고 Dart에서 리플렉션을 어떻게 사용하는지에 대해 초보자도 이해하기 쉽게 설명하겠습니다.

1. 리플렉션(Reflection)이란?

리플렉션은 프로그램이 실행되는 동안 객체나 클래스의 정보를 탐색하고, 수정하며, 메서드를 호출하거나 필드를 변경할 수 있는 기능입니다.

쉽게 말해, 코드가 자신을 들여다보고(반영하고), 그 정보를 기반으로 동작을 결정할 수 있게 해주는 기술입니다.

1.1 왜 리플렉션이 필요할까요?

리플렉션은 다음과 같은 상황에서 유용하게 사용할 수 있습니다:

  • 동적 객체 생성: 클래스 이름만 알고 있을 때, 그 클래스의 인스턴스를 생성해야 하는 경우
  • 런타임 시 메서드 호출: 프로그램 실행 중에 어떤 메서드를 호출할지 결정해야 하는 경우
  • 의존성 주입: 프레임워크에서 특정 객체를 생성하거나 구성 요소를 동적으로 주입할 때

이러한 기능들은 일반적인 프로그래밍에서는 쉽게 구현하기 어렵지만, 리플렉션을 통해 가능해집니다.

2. Dart에서의 리플렉션 사용

Dart에서는 리플렉션을 사용하기 위해 dart:mirrors 패키지를 이용합니다.

하지만 이 패키지는 웹 애플리케이션에서는 사용되지 않으며, 주로 서버나 CLI 애플리케이션에서 사용됩니다.

2.1 리플렉션의 기본 사용법

먼저, 리플렉션을 사용하기 위해 dart:mirrors 패키지를 임포트해야 합니다.

import 'dart:mirrors';

2.2 클래스의 메타데이터 탐색

리플렉션을 사용하면 클래스의 메타데이터(예: 클래스 이름, 필드, 메서드 등)에 접근할 수 있습니다.

import 'dart:mirrors';

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  void greet() {
    print('Hello, my name is $name and I am $age years old.');
  }
}

void main() {
  // Person 클래스의 인스턴스 생성
  Person person = Person('Alice', 25);

  // 리플렉션을 사용하여 person 객체의 클래스 타입 정보 가져오기
  ClassMirror classMirror = reflectClass(Person);

  // 클래스 이름 출력
  print('Class Name: ${MirrorSystem.getName(classMirror.simpleName)}');

  // 클래스의 메서드 목록 출력
  classMirror.declarations.forEach((symbol, declaration) {
    if (declaration is MethodMirror) {
      print('Method: ${MirrorSystem.getName(symbol)}');
    }
  });
}

설명

  • reflectClass(Person)을 사용하여 Person 클래스의 정보를 얻을 수 있습니다.
  • MirrorSystem.getName(classMirror.simpleName)은 클래스의 이름을 가져오는 방법입니다.
  • classMirror.declarations를 통해 클래스의 모든 메서드와 필드를 탐색할 수 있습니다.

2.3 런타임 시 메서드 호출

리플렉션을 사용하면 런타임에 특정 메서드를 동적으로 호출할 수 있습니다.

import 'dart:mirrors';

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  void greet() {
    print('Hello, my name is $name and I am $age years old.');
  }
}

void main() {
  Person person = Person('Alice', 25);

  // 리플렉션을 사용하여 person 객체 반영
  InstanceMirror instanceMirror = reflect(person);

  // greet 메서드 호출
  instanceMirror.invoke(#greet, []);
}

설명

  • reflect(person)을 사용해 person 객체를 반영(Reflect)하고, instanceMirror를 얻습니다.
  • invoke(#greet, [])은 greet 메서드를 호출하는 방법입니다. #greet은 메서드의 이름을 Symbol로 표현한 것이며, 빈 리스트 []는 메서드 인자를 나타냅니다.

3. 리플렉션의 한계와 주의점

리플렉션은 강력한 도구지만, 몇 가지 단점도 있습니다.

  • 퍼포먼스 저하: 리플렉션을 사용하면 실행 속도가 느려질 수 있습니다. 이는 리플렉션이 런타임에 동적으로 수행되기 때문입니다.
  • 코드 복잡성 증가: 코드가 복잡해지고, 디버깅이 어려워질 수 있습니다. 리플렉션을 잘못 사용하면 버그를 찾기 어려울 수 있습니다.
  • 플랫폼 제한: dart:mirrors는 웹 애플리케이션에서는 사용할 수 없습니다. 주로 서버 측에서 사용됩니다.

따라서 리플렉션은 필요한 경우에만 신중하게 사용하는 것이 좋습니다.

 

리플렉션은 Dart에서 동적으로 클래스와 객체를 탐색하고 조작할 수 있게 해주는 강력한 기능입니다. 이 글에서 설명한 기초 개념과 사용법을 이해하면, 리플렉션을 활용해 보다 유연한 코드를 작성할 수 있을 것입니다. 하지만, 리플렉션의 한계와 주의점도 꼭 고려해야 합니다. 이를 잘 활용해 더욱 효율적인 프로그램을 작성해 보세요!

구독!! 공감과 댓글은 저에게 큰 힘이 됩니다.

Starting Google Play App Distribution! "Tester Share" for Recruiting 20 Testers for a Closed Test.

 

Tester Share [테스터쉐어] - Google Play 앱

Tester Share로 Google Play 앱 등록을 단순화하세요.

play.google.com

 

 

반응형