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

# Observerパターンについて軽く
`Observer` は観測者という意味だが、どちらかというと観測される側(`Subject`)から観測者へ、どう通知するかについてまとめられたパターン。
通知側(Subject)で観測対象の事象が発生したら、観測側(Observer)へ通知(notifyObservers())し、観測側の処理を開始する(update())。
通知側と観測側を分離することによって、事象の発生とその事象に対してどう振る舞うか、が分離されるのがメリット。

# サンプルとして何を作ったか
新しくFlutterプロジェクトを作成するときに自動生成されるカウンターアプリを元に、カウントがインクリメントされたらファイル書き込みとDB書き込みするように変更し、その通知をObserverパターンを用いて行う。
(サンプルコードとしてはファイル書き込み、DB書き込みを行った、というていのログのみ記載)

# クラス図
```mermaid
classDiagram
  class Observer {
    <<abstract>> 
    +update()*
  }
  class FileWriter {
    +update()*
  }
  class DbWriter {
    +update()*
  }
  class Subject {
    <<abstract>> 
    +notifyObservers()*
    +addObserver()*
    +removeObserver()*
  }
  class _MyHomePageState {
    +notifyObservers()*
    +addObserver()*
    +removeObserver()*
  }
  class MyApp {
  }
  class MyHomePage {
  }

  Observer <|.. FileWriter
  Observer <|.. DbWriter
  Subject <|.. _MyHomePageState

  MyHomePage <-- MyApp
  _MyHomePageState <-- MyHomePage
  FileWriter <-- _MyHomePageState
  DbWriter <-- _MyHomePageState
```

# コード

[GitHub](https://github.com/kenta4327/flutter_observer) に完全版があります。

```dart:observer.dart
abstract class Observer {
  void update(int counter);
}
```

```dart:subject.dart
import 'package:flutter_observer/utils/observer.dart';

abstract class Subject {
  void addObserver(Observer observer);
  void removeObserver(Observer observer);
  void notifyObservers();
}
```

```dart:file_writer.dart
import 'package:flutter_observer/utils/observer.dart';

class FileWriter implements Observer {
  @override
  void update(counter) {
    // とりあえずログ記載のみ行う
    print('$counter をファイルに書き込み');
  }
}
```

```dart:db_writer.dart
import 'package:flutter_observer/utils/observer.dart';

class DbWriter implements Observer {
  @override
  void update(counter) {
    // とりあえずログ記載のみ行う
    print('$counter をDBに書き込み');
  }
}
```

```dart:my_home_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_observer/utils/db_writer.dart';
import 'package:flutter_observer/utils/file_writer.dart';
import 'package:flutter_observer/utils/observer.dart';
import 'package:flutter_observer/utils/subject.dart';

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> implements Subject {
  int _counter = 0;
  final List<Observer> _observers = [];

  @override
  void addObserver(Observer observer) {
    _observers.add(observer);
  }

  @override
  void removeObserver(Observer observer) {
    _observers.remove(observer);
  }

  @override
  void notifyObservers() {
    for (final observer in _observers) {
      observer.update(_counter);
    }
  }

  @override
  void initState() {
    addObserver(FileWriter());
    addObserver(DbWriter());

    super.initState();
  }

  void _incrementCounter() {
    setState(() {
      _counter++;
      notifyObservers();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
```

以上