デザインパターン (Providerパターン)

## デザインパターンとは
デザインパターン(設計パターン）とは、過去のソフトウェア設計者が発見し編み出した設計ノウハウに名前をつけ、再利用しやすいように特定の規約に従ってカタログ化したものです。

デザインパターンを利用するメリットは、**再利用性の高い柔軟な設計ができる**という点です。設計者の直感や経験などに依存していた設計が、デザインパターンを導入することで、初心者でも先人たちが詰め込んだ「知恵」を利用して設計をすることが可能になります。

もう一つのメリットとして、**技術者どうしの意思疎通が容易になる**ことが挙げられます。デザインパターンを習得している技術者どうしであれば、パターン名で設計の概要の合意を取ることが可能になります。このように、デザインパターンを学習しておくことで開発者どうしの意思疎通がスムーズになるのです。

以下は、Flutterにおける主要なデザインパターンです。

- Model-View-Controller (MVC)
- Model-View-ViewModel (MVVM)
- Provider(プロバイダー) パターン
- Bloc(ブロック) パターン
- Singleton(シングルトン) パターン
- Factory(ファクトリー) パターン
- Builder(ビルダー) パターン
- Composite(コンポジット) パターン

これらのパターンを駆使することで、開発者はアプリケーションの品質を向上させ、開発をスムーズに進めることができ、プロジェクトの規模やメンバーのスキルに応じた柔軟な設計が行えるのです。

今回は **Providerパターン** に対象を絞って解説をしていきます。

## Providerパターン
Providerとは、アプリケーション全体でデータやオブジェクトを簡単に共有・管理するための状態管理パッケージです。Googleが公式に推奨しているパッケージの一つで、シンプルかつ効率的に状態管理を行うことができるため、多くのFlutter開発者に利用されています。

### 1. 定義 
Providerパターンは、アプリケーション全体で状態やオブジェクトを共有するためのデザインパターンになります。このパターンでは、特定のデータやオブジェクトをアプリケーションのルートに近い位置で提供し、それを必要とするウィジェットツリーの下位にあるすべてのウィジェットにアクセスさせることができます。これにより、状態管理が簡素化され、コードの保守性や再利用性が向上します。

### 2. コンポーネント

- **ChangeNotifier:** データモデルの変更を通知するための基本クラスです。
`notifyListeners()` メソッドを呼び出すことで、リスナーに変更を通知します。

- **ChangeNotifierProvider:** ChangeNotifier を提供するプロバイダです。
ウィジェットツリー内で ChangeNotifier を作成し、そのインスタンスをツリー内の子ウィジェットに提供します。

- **Consumer:** Provider で提供されているデータを使用するためのウィジェットです。
状態が変更されたときに再ビルドされるウィジェットを定義します。

- **Provider.of<T>:** 指定した型のプロバイダを検索し、そのインスタンスを返します。
非常にシンプルな方法でプロバイダにアクセスできますが、ウィジェットの再ビルドは行いません。


### 3. メリット

- **シンプルなAPI:** 使いやすく直感的なAPIを提供しており、学習コストが低いです。

- **パフォーマンスの向上:** 必要な部分だけが再ビルドされるため、効率的な状態管理が可能です。
- **スケーラビリティ:** 小規模なアプリから大規模なアプリまで、スケールに応じて柔軟に対応できます。

- **再利用性の向上:** 状態管理のロジックを分離して再利用することが容易になります。

- **依存関係の管理:** 依存関係の注入が簡単に行えるため、テストやモックの設定が容易になります。

### 4. サンプルコード

```dart: Providerサンプルコード
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class CounterModel {
  int count = 0;

  void increment() {
    count++;
  }

  void decrement() {
    count--;
  }
}

class CounterViewModel extends ChangeNotifier {
  final CounterModel _counterModel = CounterModel();

  int get count => _counterModel.count;

  void increment() {
    _counterModel.increment();
    notifyListeners();
  }

  void decrement() {
    _counterModel.decrement();
    notifyListeners();
  }
}

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ChangeNotifierProvider(
        create: (context) => CounterViewModel(),
        child: CounterView(),
      ),
    );
  }
}

class CounterView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counterViewModel = Provider.of<CounterViewModel>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('MVVM Counter App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Count',
              style: Theme.of(context).textTheme.headlineLarge,
            ),
            Text(
              '${counterViewModel.count}',
              style: Theme.of(context).textTheme.headlineLarge,
            ),
          ],
        ),
      ),
      floatingActionButton: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: counterViewModel.increment,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
          SizedBox(width: 10),
          FloatingActionButton(
            onPressed: counterViewModel.decrement,
            tooltip: 'Decrement',
            child: Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}
```
- **CounterModel クラス:**
    - `CounterModel` クラスは、アプリケーションの状態を保持しています。モデルとして機能し、カウンターのビジネスロジックを管理します。
    - `count` プロパティで現在のカウントを保持し、 `increment` メソッドでカウントを増やし、 `decrement` メソッドでカウントを減らします。

- **CounterController クラス (Controller):**
    - `CounterViewModel` は `ChangeNotifier` を継承し、モデルを操作するためのメソッドを提供しています。
    - `increment` や `decrement` メソッドが呼びされると、内部の `CounterModel` のメソッドを呼び出し、 `notifyListeners` を使ってリスナーに状態の変更通知します。
    - `notifyListners` を使用することにより、 `CounterViewModel` に依存しているUIコンポーネントが自動的に再描画されます。

- **CounterPage クラス (View):**
    - `ChangeNotifierProvider` を使用して、 `CounterViewModel` を提供し、これを `CounterView` に渡しています。
    - `ChangeNotifierProvider` を使用することにより、 `CounterViewModel` を提供し、ウィジェットツリー全体でアクセス可能になります。
    - `Provider.of<CounterViewModel>(context)` を使って、 `CounterViewModel` にアクセスし、値を取得して表示します。

## まとめ
Providerパターンは、Flutterアプリケーションにおけるシンプルな状態管理方法です。
このパターンは、アプリケーション全体でデータやオブジェクトを
簡単に共有・管理するためのもので、Googleが推奨するパッケージの一つです。

主要なコンポーネントとして、 `ChangeNotifier` 、 `ChangeNotifierProvider` 、 `Consumer` 、 `Provider.of<T>` があり、これらを組み合わせることで、柔軟な状態管理が可能になります。

このパターンを利用することで、パフォーマンスの向上、スケーラビリティ、
再利用性の向上、依存関係の管理を容易に行えるため、これを機にぜひ使用してみてください。

## 告知
最後にお知らせとなりますが、イーディーエーでは一緒に働くエンジニアを
募集しております。詳しくは採用情報ページをご確認ください。

https://eda-inc.jp/recruit/

みなさまからのご応募をお待ちしております。