DependencyInjectionパターンについて調べたのでFlutterでサンプルを作ってみた

# DependencyInjectionパターンについて軽く
オブジェクト生成時に、自分でnewせずに外部から引数として生成対象のオブジェクトをもらうパターン。
そうすることにより、使用オブジェクトの種類が変更になっても自身への影響がなくなる。

# サンプルとして何を作ったか

[FactoryMethodパターンの時のサンプル](https://qiita.com/kenta4327/items/93ece56ee61a3526cfb9#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%95%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%9F%E3%81%8B) をDependencyInjectionパターンにする

> 保存するボタンと読み込むボタンがある画面で、
保存するボタンを押すと、テキストボックスにある文字列を保存して、
読み込むボタンを押すと、保存先から文字列を読み込んで出力する、
というアプリ。

追加で、
読み込む時は「☆☆〜〜〜☆☆」で対象文字列を囲んだ状態で出力することとし、
この対象文字列を扱っているクラスをDependencyInjectionパターンで生成することとする。

# クラス図

```mermaid
classDiagram
  class TextUtil {
    <<abstract>>
    +save()
    +read()
  }
  class FileTextUtil {
    +save()
    +read()
  }
  class DecorationCharacter {
    <<abstract>>
    +getDecoration()
  }
  class DecorationCharacterStar {
    +getDecoration()
  }
  class MyApp {
  }
  class MyHomePage {
  }
  class _MyHomePageState {
  }

  TextUtil <|.. FileTextUtil
  DecorationCharacter <|.. DecorationCharacterStar

  DecorationCharacter <-- FileTextUtil

  MyHomePage <-- MyApp
  _MyHomePageState <-- MyHomePage
  FileTextUtil <-- _MyHomePageState
  DecorationCharacterStar <-- _MyHomePageState : 注入
```

# コード
[GitHub](https://github.com/kenta4327/flutter_dependency_injection) に完全版があります。

```dart:text_util.dart
abstract class TextUtil {
  void save(text);
  Future<String> read();
}
```

```dart:file_text_util.dart
import 'dart:io';

import 'package:flutter_dependency_injection/utils/decoration_character.dart';
import 'package:flutter_dependency_injection/utils/text_util.dart';
import 'package:path_provider/path_provider.dart';

class FileTextUtil implements TextUtil {
  DecorationCharacter? _decorationCharacter;

  FileTextUtil(DecorationCharacter decorationCharacter) {
    _decorationCharacter = decorationCharacter;
  }

  @override
  void save(text) async {
    final directory = await getApplicationDocumentsDirectory();
    final path = directory.path;
    final file = File('$path/hoge.txt');

    // ファイルがなかったら生成する
    if (!await file.exists()) {
      await file.create();
    }
    await file.writeAsString(text);
  }

  @override
  Future<String> read() async {
    final directory = await getApplicationDocumentsDirectory();
    final path = directory.path;
    final file = File('$path/hoge.txt');

    // ファイルがあった時だけ読み込む
    if (await file.exists()) {
      final dataTmp = await file.readAsString();
      final decorationCharacter = _decorationCharacter?.getDecoration();
      final data = '$decorationCharacter$dataTmp$decorationCharacter';
      return data;
    }

    return '';
  }
}
```

```dart:decoration_character.dart
abstract class DecorationCharacter {
  String getDecoration();
}
```

```dart:decoration_character_star.dart
import 'package:flutter_dependency_injection/utils/decoration_character.dart';

class DecorationCharacterStar implements DecorationCharacter {
  final _decorationCharacter = '☆☆';

  @override
  String getDecoration() {
    return _decorationCharacter;
  }
}
```

```dart:main.dart
  :
  : // 割愛
  :
class _MyHomePageState extends State<MyHomePage> {
  final _textController = TextEditingController();
  String _outputText = '';
  TextUtil? _textUtil;

  @override
  void initState() {
    super.initState();

    _textUtil = FileTextUtil(DecorationCharacterStar());
  }
  :
  : // 割愛
  :
```

以上