2015-05-08 13 views
18

Trong một dự án tôi đang làm việc trên tôi có 2 lớp học mà phụ thuộc rất nhiều vào nhau:dao găm 2 tròn dependancy

@Singleton 
class WorkExecutor { 
    @Inject Provider<ExecutionServices> services; 
    ... 
    public void execute(Work w){ 
     w.execute(services.get()); 
     ... 
    } 
    ... 
} 

class ExecutionServicesImpl implements ExecutionServices { 
    @Inject WorkExecutor executor; 
    ... 
} 

Ý tưởng là khi thực hiện một tác phẩm, tác phẩm có quyền truy cập vào một số dịch vụ - một trong số đó là bản thân người thực thi để một tác phẩm có thể thực thi các tác phẩm phụ.

Như người ta có thể thấy, có một phụ thuộc vòng tròn ở đây, nhưng tôi thấy rất khó để phá vỡ nó.

Vấn đề chính là WorkExecutor không thực sự cần một thể hiện của đối tượng ExecutionServices tại thời gian xây dựng đồ thị nhưng chỉ có một nhà cung cấp được sử dụng sau này. Thật đáng buồn, Dagger không biết rằng WorkExecutor sẽ không gọi nhà cung cấp ExecutionServices từ constructor của lớp để nó đoán rằng ExecutionServices phụ thuộc vào WorkExecutor và ngược lại.

Một giải pháp khả thi mà tôi tìm thấy là để xác định một mô-đun và thành phần theo cách sau:

interface DelayedProvider<T> extends Provider<T>{} 

@Module 
class AppModule { 
    Provider<ExecutionServices> delayedProvider = null; 

    @Provides DelayedProvider<ExecutionServices> provideDelayed() { 
     return() -> delayedProvider.get(); 
    } 

    @Provides @Named("late-binding-conf") Void latebindingConf(Provider<ExecutionServices> eager){ 
     this.delayedProvider = eager; 
     return null; //notice we returning Void and not void 
    } 

} 

@Component(modules=AppModule.class) 
interface AppComponent { 
    App app(); 
    @Named("late-binding-conf") Void configureLateBinding(); 
} 

và sau đó tôi sẽ thay đổi các lớp học ban đầu là:

@Singleton 
class WorkExecutor { 
    @Inject DelayedProvider<ExecutionServices> services; 
    ... 
    public void execute(Work w){ 
     w.execute(services.get()); 
     ... 
    } 
    ... 
} 

class ExecutionServicesImpl implements ExecutionServices { 
    @Inject WorkExecutor executor; 
    ... 
} 

Và sau đó theo thứ tự để tạo ứng dụng của tôi, tôi phải làm:

AppComponent acomp = DaggerAppComponent.create(); 
App = acomp.app(); 
acomp.configureLateBinding(); 

Nhưng tôi không chắc đây là hành động - Có cách nào tốt hơn không?

+0

Tôi gặp sự cố tương tự. Bạn đã bao giờ tìm thấy một giải pháp tốt hơn? – KennethJ

+0

@KennethJ, thật đáng buồn là không .. – bennyl

+2

Tại sao 'ExecutionServicesImpl' lại cần' WorkExecutor'? Bạn nói điều này là để một công việc có thể thực hiện các subworks. Bạn không thể chỉ có 'WorkExecutor' tự chuyển sang phương thức' execute' 'execute' thay vì nó là thành viên của' ExecutionServicesImpl'? – Frans

Trả lời

1

Tôi không nghi ngờ OP sẽ như thế này, vì bạn muốn một cách để làm điều gì đó 'sai', làm việc 'đúng'. Điều đó không thể thực sự được. Bất cứ khi nào bạn gặp phải sự phụ thuộc vòng tròn, giải pháp "đúng" là để cấu trúc lại để loại bỏ sự phụ thuộc đó.

Trong trường hợp của bạn, WorkExecutor là một singleton nên có lẽ nó cần phải giữ nguyên. ExecutionServicesImpl sau đó nên được sửa đổi để loại bỏ sự phụ thuộc vào WorkExecutor. Không biết chi tiết về mã, người ta không thể nói quá nhiều. Tuy nhiên, có một ExecutionService được độc lập với nó là "công nhân" là giảm khớp nối và có thể là một điều rất tốt trong thời gian dài.

0

tại sao ExecutionServicesImpl phụ thuộc vào WorkExecutor?

Hiển thị nhiều lõi hơn, ExecutionServices cũng giống như Singleton, tại sao nó phụ thuộc vào nhau để hoạt động chính xác?

WorkExecutor có vẻ như một thứ gì đó mà bạn có thể chuyển đến ExecutionService dưới dạng WorkExecutor sẽ được tiêm ở một nơi khác, có thể là hình ảnh sử dụng Service.

Tôi không biết, hiển thị nhiều mã hơn và có lẽ đó là câu trả lời, có vẻ phức tạp.

0

Tôi gặp phải tình huống trong dự án Swing, nơi đối tượng bên thứ ba phụ thuộc vào JFrameJFrame phụ thuộc vào đối tượng bên thứ ba để tạo ngăn nội dung. Tôi đã đưa ra giải pháp này, nhưng cuối cùng quyết định đóng vòng lặp trong phương pháp chính của tôi sau khi đồ thị đối tượng được xây dựng.Về cơ bản, tôi đã tạo ra hai tên JFrame nhà cung cấp, thứ hai phụ thuộc vào ngày đầu tiên và trở về cùng một ví dụ:

@Provides 
@Singleton 
@Named("DO_NOT_INJECT") 
JFrame mainWindowIncomplete() { 
    return new JFrame(); // after setting it up 
} 

@Provides 
@Singleton 
CControl dockControl(@Named("DO_NOT_INJECT") JFrame mainWindow) { 
    return new CControl(mainWindow); 
} 

@Provides 
@Singleton 
@Named("MAIN_WINDOW") 
JFrame mainWindow(@Named("DO_NOT_INJECT") JFrame mainWindow, CControl dockControl) { 
    mainWindow.add(dockControl.getContentArea()); 
    return mainWindow; 
} 

Để làm việc này, các nhà cung cấp thứ hai sẽ phải được sử dụng ít nhất một lần. Bạn có thể đảm bảo điều này bằng cách thêm bộ định danh riêng tư của gói vào danh sách đầu tiên như được mô tả trong this answer.

Các vấn đề liên quan