En | 日本語
Flutter プロジェクトを オニオン・アーキテクチャ ではじめるスターター・キットとしてのサンプルコードです。
全体的に Work in Progress であり、アプリとしてはまだ動作いたしません。順次アップデート予定です。
- Flutter v3.3
- Riverpod
- Firestore
- SQLite
- ほか、おもなパッケージ
Flutter/Dart のプロジェクトにおいて、オニオン・アーキテクチャを採用することは可能です。Dart の持つオブジェクト指向言語としての性質を利用することで、
ドメインモデルに関する知識を表現するのがドメイン層の責務です。
- エンティティ
エンティティを Dart で表現するために、equatable を利用してオブジェクトの同一性を定義できます。
次の例では、Book
クラスの id
プロパティのみでオブジェクトの同一性を表現しています。
class Book with EquatableMixin {
const Book({
required this.id,
required this.title,
});
@override
List<Object> get props => [id];
final String id;
final String title;
}
- バリュー・オブジェクト
TBD
- リポジトリ(インターフェース)
リポジトリは、エンティティの永続化を行う役割を持つクラスです。リポジトリのインターフェースはドメイン層に定義します。Dart では、abstract class
を用いてインターフェースを定義できます。
abstract class BookRepository {
Future<Book?> findById(String id);
Future<List<Book>> findAll();
Future<void> save(Book book);
}
ユースケース(またはアプリケーション)は、ユースケース・シナリオの実現を責務とするレイヤーです。
インターフェースと実装クラスを分けて定義します。
abstract class BookUseCase {
Future<Book?> getBookById(String id);
Future<List<Book>> getBooks();
Future<Book> createBook({
required String title,
});
}
class BookUseCaseImpl implements BookUseCase {
const BookUseCaseImpl(this._bookRepository);
final BookRepository _bookRepository;
@override
Future<Book?> getBookById(String id) {
return _bookRepository.findById(id);
}
// ...
}
- リポジトリ(実装)
インフラ層では、特定のインフラや外部サービスに依存する実装を定義するレイヤーです。ドメイン層で定義したリポジトリのインターフェースに対応する実装はここで行います。
class SQLiteBookRepository implements BookRepository {
late Database db;
@override
Future<Book?> findById(String id) async {
final rows = await db.query(
SQLiteBookDTO.tableName,
columns: SQLiteBookDTO.columns,
where: 'id = ?',
whereArgs: [id],
);
if (rows.isEmpty) {
return null;
}
return SQLiteBookDTO.fromJson(rows.first).toEntity();
}
-
View
-
View Model
FlutterKaigi 2022 発表資料 : Flutter アプリの将来のインフラ移行に備える 疎結合なソフトウェア・アーキテクチャ(イベント開催後に公開予定です)