はじめに
「抽象化ってなんや?」
「インターフェースとかファクトリーって、結局どういうこと?」
そんな疑問を持っている方向けに、実例を通して抽象化の考え方を解説します!
抽象化とは
抽象化とは、詳細な実装を隠して、共通の使い方だけを提供するという考え方です。
コードを書く上で、「呼び出す側が細かい実装を知らなくても済む」ようにするための設計テクニックです。
Flutterでの具体例
目的:環境によって保存処理を切り替えたい
例えば、以下のようなケースを考えます。
- 通常はセキュアなストレージに保存したい
- テスト中はモックを使いたい
- Webでは別のストレージ実装を使いたい
これを毎回 if
文で分岐するのではなく、抽象化とファクトリーパターンを使って整理します。
1. 抽象クラス(共通のインターフェース)
abstract class AppStorage {
Future<void> save(String key, String value);
Future<String?> load(String key);
}
2. 通常時の実装(セキュアストレージ)
class SecureStorage implements AppStorage {
@override
Future<void> save(String key, String value) async {
// 保存処理
}
@override
Future<String?> load(String key) async {
// 取得処理
}
}
3. テスト用のモック実装
class MockStorage implements AppStorage {
final Map<String, String> _storage = {};
@override
Future<void> save(String key, String value) async {
_storage[key] = value;
}
@override
Future<String?> load(String key) async {
return _storage[key];
}
}
4. ファクトリーで環境ごとに実装を切り替える
import 'dart:io';
import 'package:flutter/foundation.dart';
class StorageFactory {
AppStorage create() {
if (kIsWeb) {
return WebStorage(); // Web向けの仮実装
}
if (Platform.environment.containsKey('FLUTTER_TEST')) {
return MockStorage();
}
return SecureStorage();
}
}
なぜこれが抽象化なのか?
この構成では、呼び出す側(利用側)は AppStorage
という抽象クラスにしか依存していません。
そのため、実際にどのストレージ(セキュア/モック/Web)が使われているかは知らなくてよいのです。
これが「詳細を隠す」という抽象化の考え方です。
この設計の利点
-
テストしやすい
テスト実行時に自動的にモック実装に切り替わる -
保守性が高い
新しい実装(たとえばクラウド同期型のストレージなど)を追加しても、利用側を変更する必要がない -
拡張しやすい
AppStorage
を実装した新しいクラスを追加するだけで対応可能
まとめ
抽象化とは、実装の詳細を隠し、共通のインターフェースを通じて使えるようにすること。
Flutterでは、テストやマルチプラットフォーム対応の際によく使われます。
ポイントは次の3つです
- 抽象クラス(インターフェース)を作る
- 用途に応じた実装クラスを用意する
- ファクトリーパターンなどで環境に応じて実装を返す
以上、ご覧いただきありがとうございました!