これは、経験豊富なソフトウェアエンジニアにとっては簡単な質問です。
私は現在、ボブおじさんによる本 Clean Architecture を読んでおり、Javaプロジェクトにクリーンアーキテクチャを実装しようとしています。
さて、私のプロジェクトでは、本の第17章で説明されているのとまったく同じ状況に遭遇しました。
赤い線は、高レベルのビジネスルールコンポーネントと低レベルのデータベースコンポーネントの境界です。高レベルコンポーネントの一部であるDatabaseInterface
のおかげで、低レベルコンポーネントに実装されているため、依存関係ルールは満たされています。
ただし、BusinessRules
は、依存関係ルールに違反せずにDatabaseInterface
を実装するオブジェクトのインスタンスをどのように取得できますか?
実装クラスDatabaseAccess
は低レベルコンポーネントにあり、高レベルコンポーネントは低レベルコンポーネントのクラスについて何も認識していません。
言い換えると、DatabaseAccess
内でBusinessRules
オブジェクトをインスタンス化することはできません。これは、依存関係ルールに違反するためです。
この問題は通常どのように解決されますか?
注:
同じ状況が第18章でも説明されています。
そしてここでも、依存関係ルールに違反せずにClient
がServiceImpl
のインスタンスを取得する方法を教えてください。
この本は、これが実際にどのように行われるかについてのヒントを与えていません。この状況を解決するための正しい戦略を知りたいと思います。
アプリケーション構造には、他のすべてのコンポーネント/ライブラリについて「認識する」1つの「エントリポイント」コンポーネント(main
メソッドを使用)が必要です。
エントリポイントコンポーネントの責任は、高レベルの抽象化と低レベルの実装を接着することです。
.----------------. .----------------<I>-. .-----------------.
| Business rules | ----> | Database interface | <|--- | Database access |
'----------------' '--------------------' '-----------------'
^ ^ ^
| | |
| | |
| .-------------. |
---------------- | Entry point | -------------------
'-------------'
エントリポイントでは、ビジネスルールオブジェクトをインスタンス化して、実装の詳細を知るビジネスルールなしでデータベースインターフェースの実装を渡すことができます。
public void main()
{
// MyDatabase implements IDataAccess
IDataAccess dataAccess = new MyDatabase(connectionString);
// BusinessRules expect an instance of IDataAccess as constructor parameter
MyBusinessRule rule = new MyBusinessRule(dataAccess);
}
このアプローチは、依存性注入としてよく知られています。このプロセスを自動化する依存性注入フレームワークがたくさんあります。ただし、学習のためには、手動で行い、考えられる問題を自分で解決するとよいでしょう。
典型的なアプローチは、ある種のファクトリーを使用することです(Wikipedia:Factory Method Pattern)。高レベルのコードはファクトリからオブジェクトを要求し、ファクトリはオブジェクトを作成する必要がある具体的なクラスを認識しています。
編集:(インターフェースではなく)ファクトリーの実装はアプリケーションに固有であり、構成の一部です。ビジネスロジックと下位層を「接着」しますが、どちらにも含まれていません。
ファクトリアプローチは、下位層のオブジェクトを構築する必要がある決定、いつ、どのくらいの頻度でビジネスロジックを実行する必要がある場合に役立ちます。他の場合では、ビジネスロジックの起動時にオブジェクトにビジネスロジックを提供するなど、制御メカニズムの他の反転を使用できます(Fabioからの回答を参照)。