[flutter] 플러터에서 의존성 주입과 Injectable의 관계에 대한 예시 프로젝트

의존성 주입(Dependency Injection, DI)은 소프트웨어 디자인 패턴 중 하나로, 의존 관계를 갖는 객체 사이의 결합도를 낮추기 위해 사용됩니다. Flutter 애플리케이션에서 의존성 주입을 구현하려면 보통 get_it과 같은 라이브러리를 사용합니다. 이번 예시에서는 get_it을 사용하여 DI를 구현하고, injectable이라는 패키지를 사용하여 의존성 주입을 관리하는 방법에 대해 알아보겠습니다.

1. 프로젝트 설정

먼저, Flutter 프로젝트를 생성하고 get_itinjectable 패키지를 추가해야 합니다. pubspec.yaml 파일에 아래와 같이 의존성을 추가합니다:

dependencies:
  flutter:
    sdk: flutter
  get_it: ^4.0.4

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^1.10.4
  injectable_generator: ^1.2.0

의존성을 추가한 후, pub get 명령어를 실행하여 패키지를 다운로드합니다.

2. 의존성 주입 설정

이제 의존성 주입을 설정하는 단계입니다. main.dart 파일을 열고 아래와 같이 작성합니다:

import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';

import 'injection.config.dart';

void setupInjection() {
  configureInjection(Environment.prod);
}

void main() {
  setupInjection();
  runApp(MyApp());
}

setupInjection 함수는 의존성 주입을 설정하는 역할을 합니다. configureInjection 함수를 호출하고 환경을 Environment.prod로 설정했습니다. Environment.proddevelopment, staging, production 등의 환경에 따라 의존성을 설정하는 데 사용되는 값입니다.

3. 의존성 주입 및 사용

이제 의존성 주입을 사용하여 객체를 생성하고 이를 사용하는 방법에 대해 알아보겠습니다.

먼저, 예시로 UserService 클래스를 만들어보겠습니다. services/user_service.dart 파일을 생성하고 아래의 코드를 작성합니다:

abstract class UserService {
  void login(String email, String password);
}

@lazySingleton
@Injectable(as: UserService)
class UserServiceImpl implements UserService {
  @override
  void login(String email, String password) {
    // 로그인 로직 구현
  }
}

UserService는 추상 클래스로, 다양한 프로토콜을 가진 애플리케이션의 다른 부분과의 통신을 위한 인터페이스 역할을 합니다. UserServiceImplUserService를 구현한 클래스로 실제로 로그인 로직을 구현하고 있습니다. @lazySingleton은 한 번 생성된 객체를 계속 사용하도록 하는 주석입니다.

다음으로, 위에서 작성한 UserService의 의존성을 주입받아 사용하기 위해 화면에 버튼을 추가해보겠습니다. main.dart 파일을 열고 아래와 같이 수정합니다:

import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';

import 'injection.config.dart';
import 'services/user_service.dart';

void setupInjection() {
  configureInjection(Environment.prod);
  GetIt.instance.registerLazySingleton<UserService>(() => UserServiceImpl());
}

void main() {
  setupInjection();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final UserService userService = GetIt.instance<UserService>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dependency Injection Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dependency Injection Example'),
        ),
        body: Center(
          child: FlatButton(
            child: Text('Login'),
            onPressed: () {
              userService.login('example@email.com', 'password');
            },
          ),
        ),
      ),
    );
  }
}

MyApp 클래스에서 UserService의 인스턴스를 받아오기 위해 GetIt.instance<UserService>()를 사용합니다. 버튼을 누르면 UserServicelogin 메서드가 호출되도록 구현했습니다. 이제 앱을 실행하고, 버튼을 클릭하면 UserServicelogin 메서드가 호출되는지 확인해보세요.

4. 의존성 주입 설정 파일 생성

마지막으로, injectable 패키지를 사용하여 의존성 주입 설정 파일을 생성하는 방법에 대해 알아보겠습니다.

먼저 프로젝트 루트 디렉토리에서 injection.dart 파일을 생성하고 아래와 같이 작성합니다:

import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';

import 'services/user_service.dart';

final GetIt getIt = GetIt.instance;

@injectableInit
void configureInjection(String environment) => $initGetIt(getIt, environment: environment);

@module
abstract class InjectableModule {
  @lazySingleton
  UserService get userService => UserServiceImpl();
}

이제 프로젝트 루트 디렉토리에서 터미널을 열고 아래 명령어를 실행하여 의존성 주입 설정 파일을 생성합니다:

flutter pub run build_runner build

이 명령어는 build_runner를 실행하여 injectable으로 정의된 클래스들을 분석하고, 의존성 주입 설정 파일을 생성합니다. 생성된 injection.config.dart 파일에는 의존성 주입 설정이 기록됩니다. 이제 main.dart 파일에서 import 'injection.config.dart';를 추가하여 설정 파일을 불러와 사용할 수 있습니다.

이제 예시 프로젝트에서 의존성 주입 및 Injectable의 관계에 대한 정보를 알게 되었습니다. 이를 활용하여 본인의 플러터 프로젝트에 의존성 주입을 구현해보세요!


참고 문서: