Dartのextensionの使い方

# extensionを使ってみよう

[公式のリンク](https://dart.dev/guides/language/extension-methods)

そもそもextensionとは、既存のクラスに対してメソッドを追加する機能です。

使い方は以下の通りです。

```dart
extension 名前 on 型 {
  // 拡張メソッド
  void メソッド名() {
    // 処理
  }
}
```

BuildContextに拡張メソッドを追加する例を示します。

```dart
import 'package:flutter/material.dart';

extension ContextEx on BuildContext {
  // スナックバーを表示する
  void showSnackBar(String message) {
    // 引数にthisを指定することで、このメソッドを呼び出したコンテキストを取得できる
    ScaffoldMessenger.of(this).showSnackBar(SnackBar(
      content: Text(message),
    ));
  }

  // ダイアログを表示する
  // ジェネリティクスにTを指定することで、戻り値の型を指定できる
  Future<T?> showAlertDialog<T>({
    required String title,
    required String content,
    required List<Widget> actions,
  }) async {
    return showDialog<T>(// showDialogメソッドはFuture<T>を返す
      context: this,// 引数にthisを指定することで、このメソッドを呼び出したコンテキストを取得できる
      builder: (context) => AlertDialog(
        title: Text(title),
        content: Text(content),
        actions: actions,
      ),
    );
  }
}
```

## 時間を扱うDateTimeクラスに拡張メソッドを追加する例を示します。

```dart
// 時間を扱う拡張メソッドを定義するファイル
extension DateTo on DateTime {
  // 年月日を表示する
  String toFormatString() {
    // thisは省略できる
    return "$year年$month月$day日";
  }

  // 曜日を表示する
  String toWeekdayString() {
    // 書いてある数字は、DateTimeクラスの定数
    switch (weekday) {
      case 1:
        return "月";
      case 2:
        return "火";
      case 3:
        return "水";
      case 4:
        return "木";
      case 5:
        return "金";
      case 6:
        return "土";
      case 7:
        return "日";
      default:
        return "";
    }
  }
}
```

このように拡張メソッドを定義することで、以下のように呼び出すことができます。

```dart
import 'package:flutter/material.dart';
import 'package:widget_cook/extension/date_extension.dart';
import 'package:widget_cook/extension/extension.dart';

class ExtensionCook extends StatelessWidget {
  const ExtensionCook({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // 時間のの拡張メソッドを使う
        title: Text(DateTime.now().toFormatString()),
      ),
      body: Center(
        child: Column(
          children: [
            // 今日の曜日を表示する
            Text(DateTime.now().toWeekdayString()),
            const SizedBox(height: 10),
            ElevatedButton(
                onPressed: () {
                  // 使うときは、context.メソッド名()で呼び出せる
                  context.showSnackBar("スナックバー");
                },
                child: const Text("スナックバー")),
            const SizedBox(height: 10),
            ElevatedButton(
                onPressed: () {
                  context.showAlertDialog(
                    title: "タイトル",
                    content: "コンテンツ",
                    actions: [
                      TextButton(
                        onPressed: () {
                          Navigator.pop(context);
                        },
                        child: const Text("キャンセル"),
                      ),
                      TextButton(
                        onPressed: () {
                          Navigator.pop(context);
                        },
                        child: const Text("OK"),
                      ),
                    ],
                  );
                },
                child: const Text("ダイアログ"))
          ],
        ),
      ),
    );
  }
}
```

**実行するとこんな感じになります**
2023年10月13日の時間の情報と、曜日の情報、ボタンを押すとスナックバーとダイアログを出す関数を作ることができました!

![スクリーンショット 2023-10-13 12.32.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303722/70d91b33-dfe9-1b65-a0f3-13ef42666908.png)

![スクリーンショット 2023-10-13 12.42.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303722/44eb80c2-29f6-b0ec-5fe1-049cba36942f.png)

![スクリーンショット 2023-10-13 12.42.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303722/7f6d9b43-26ed-726e-d699-04a2668c88b4.png)

## 最後に
拡張メソッドを使うことで、コードをスッキリさせることができます。複数のファイルで使う場合は、extensionフォルダを作成して、そこにまとめると良いでしょう。これで再利用性の高いコードを書くことができます。