あなたの質問を正しく理解していることを願っています。
依存関係の注入
いいえ、依存関係をすべてのレイヤーに渡すわけではありません。それらと直接対話するレイヤーにのみそれらを渡します。例えば:
public class PaymentHandler {
private customerRepository;
public PaymentHandler(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
public void handlePayment(CustomerId customerId, Money amount) {
Customer customer = customerRepository.findById(customerId);
customer.charge(amount);
}
}
public interface CustomerRepository {
public Customer findById(CustomerId customerId);
}
public class DefaultCustomerRepository implements CustomerRepository {
private Database database;
public CustomerRepository(Database database) {
this.database = database;
}
public Customer findById(CustomerId customerId) {
Result result = database.executeQuery(...);
// do some logic here
return customer;
}
}
public interface Database {
public Result executeQuery(Query query);
}
PaymentHandler
は のことを認識せずDatabase
、 とのみ会話しCustomerRepository
ます。の注入はDatabase
リポジトリ層で停止します。
コードの可読性
フレームワークやライブラリを使用せずに手動でインジェクションを行うと、多くのボイラープレート コードを含む Factory クラスになってしまう可能性がreturn new D(new C(new B(), new A());
あります。この問題を解決するために、Guiceのような DI フレームワークを使用して、非常に多くのファクトリを作成しないようにする傾向があります。
ただし、実際に作業/ビジネス ロジックを実行するクラスの場合は、直接の共同作業者とのみ会話し、必要な作業を行うため、より読みやすく理解しやすいものにする必要があります。
単体テスト
「トップ」レイヤーとは、PaymentHandler
クラスを意味すると思います。この例では、スタブ クラスを作成し、それに対してチェックできるオブジェクトをCustomerRepository
返してから、スタブを に渡して、正しい金額が請求されているかどうかをチェックできます。Customer
PaymentHandler
一般的な考え方は、テスト対象のクラス (この例ではクラス) の動作を安全にアサートできるように、出力を制御するために偽のコラボレーターを渡すことPaymentHandler
です。
インターフェイスを使用する理由
上記のコメントで述べたように、具体的なクラスではなくインターフェイスに依存する方が望ましいです。インターフェイスは、より優れたテスト容易性 (モック/スタブが容易) と簡単なデバッグを提供します。
お役に立てれば。