Vì vậy, tôi hiện đang thiết kế lại ứng dụng Android của tôi để sử dụng Dagger. Ứng dụng của tôi lớn và phức tạp và gần đây tôi đã xem xét kịch bản sau:Sử dụng Dagger để tiêm phụ thuộc vào các nhà thầu
Đối tượng A yêu cầu một cá thể DebugLogger đặc biệt là ứng cử viên hoàn hảo để tiêm. Thay vì đi vòng quanh logger, tôi chỉ có thể tiêm nó thông qua hàm tạo của A. Điều này trông giống như sau:
class A
{
private DebugLogger logger;
@Inject
public A(DebugLogger logger)
{
this.logger = logger;
}
// Additional methods of A follow, etc.
}
Điều này có ý nghĩa. Tuy nhiên, A có nhu cầu được xây dựng bởi một lớp B. Nhiều trường hợp của A phải được xây dựng, vì vậy sau cách làm việc Dagger, tôi đơn giản tiêm một Provider<A>
vào B:
class B
{
private Provider<A> aFactory;
@Inject
public B(Provider<A> aFactory)
{
this.aFactory = aFactory;
}
}
Ok, tốt cho đến nay. Nhưng chờ đợi, đột nhiên Một nhu cầu đầu vào bổ sung, chẳng hạn như một số nguyên được gọi là "số lượng" đó là quan trọng để xây dựng của nó. Bây giờ, nhà xây dựng của tôi cho A cần phải trông như thế này:
@Inject
public A(DebugLogger logger, int amount)
{
...
}
Đột nhiên tham số mới này can thiệp vào việc tiêm. Hơn nữa, ngay cả khi điều này đã làm việc, sẽ không có cách nào cho tôi để vượt qua trong "số tiền" khi lấy một trường hợp mới từ nhà cung cấp, trừ khi tôi nhầm. Có một số điều tôi có thể làm ở đây, và câu hỏi của tôi là câu hỏi nào là tốt nhất?
Tôi có thể tái cấu trúc A bằng cách thêm phương thức setAmount()
được dự kiến sẽ được gọi sau hàm tạo. Tuy nhiên, điều này là xấu, bởi vì nó buộc tôi phải trì hoãn việc xây dựng A cho đến khi "số tiền" được điền vào. Nếu tôi có hai tham số, "số lượng" và "tần suất", thì tôi sẽ có hai người định cư, có nghĩa là phức tạp kiểm tra để đảm bảo rằng việc xây dựng hồ sơ xin việc của A sau khi cả hai setters được gọi, hoặc tôi sẽ phải bổ sung được nêu ra một phương pháp thứ ba vào hỗn hợp, như vậy:
(Somewhere in B):
A inst = aFactory.get();
inst.setAmount(5);
inst.setFrequency(7);
inst.doConstructionThatRequiresAmountAndFrequency();
các thay thế khác là tôi không sử dụng constructor dựa trên tiêm và đi với tiêm dựa trên trường. Nhưng bây giờ, tôi phải công khai lĩnh vực của mình. Điều này không tốt với tôi, bởi vì bây giờ tôi bắt buộc phải tiết lộ dữ liệu nội bộ của các lớp học của tôi cho các lớp khác.
Cho đến nay, giải pháp duy nhất có phần thanh lịch tôi có thể nghĩ đến là sử dụng tiêm lĩnh vực dựa trên các nhà cung cấp, như vậy:
class A
{
@Inject
public Provider<DebugLogger> loggerProvider;
private DebugLogger logger;
public A(int amount, int frequency)
{
logger = loggerProvider.get();
// Do fancy things with amount and frequency here
...
}
}
Thậm chí vẫn còn, tôi không chắc chắn về thời gian, kể từ khi tôi m không chắc chắn nếu Dagger sẽ tiêm nhà cung cấp trước khi constructor của tôi được gọi.
Có cách nào tốt hơn không? Tôi chỉ thiếu một cái gì đó về cách Dagger hoạt động?
Cảm ơn bạn đã phản hồi nhanh chóng. Mẫu nhà máy bạn đã mô tả có vẻ giống như cách tiếp cận tốt nhất. Tôi cũng đã nhận ra rằng nếu Dagger hỗ trợ tiêm trường riêng, nó sẽ dễ dàng cho phép những gì tôi đang cố gắng thực hiện. Tôi tự hỏi tại sao đó không phải là một phần thiết kế ban đầu của Dagger? Tôi giả sử Dagger tiêm sử dụng sự phản chiếu. Nếu vậy thì các trường tư nhân sẽ không có vấn đề gì, đúng không? – Alex
Dagger rơi trở lại phản xạ nhưng đó không phải là phương tiện tiêm chính. Nó tạo ra mã trực tiếp thiết lập các trường hoặc gọi các hàm tạo của bạn. Như vậy nó hoạt động giống như bất kỳ đoạn mã nào khác trong cây nguồn của bạn và không thể truy cập các thành viên 'private'. –
Và một số người quản lý bảo mật sẽ phá vỡ sự phản ánh dựa trên việc thay đổi khả năng truy cập trong các lớp học của bạn. –