2015-05-08 4 views
18

В проекте я работаю у меня есть 2 классов, которые сильно зависят друг от друга:Кинжал 2 круговой зависимостях

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

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

Идея заключается в том, что при выполнении работы, работа имеет доступ к нескольким услугам - один из них - сам исполнитель, так что работа будет выполнена для выполнения субработ.

Как видно, здесь существует круговая зависимость, но одна из которых мне очень трудно сломать.

Основная проблема заключается в том, что WorkExecutor фактически не нужен экземпляр объекта ExecutionServices во время построения графика, а только поставщик, который будет использоваться позже. К сожалению, Кинжал не знает, что WorkExecutor не будет вызывать поставщик ExecutionServices из конструктора класса, поэтому он предполагает, что ExecutionServices зависит от WorkExecutor и наоборот.

Одно из возможных решений, которые я нашел, чтобы определить модуль и компонент следующим образом:

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(); 
} 

, а затем я модифицирует оригинальные классы быть:

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

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

, а затем в порядке для создания моего приложения, которое я должен сделать:

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

Но я не уверен, что это правильно курс действий - есть ли лучший способ?

+0

У меня такая же проблема. Вы когда-нибудь находили лучшее решение? – KennethJ

+0

@ KennethJ, к сожалению нет .. – bennyl

+2

Зачем «ExecutionServicesImpl» нужен «WorkExecutor»? Вы говорите, что это так, что работа может выполнять суб-объекты. Не могли бы вы просто передать 'WorkExecutor' самому методу' execute' 'Work' вместо того, чтобы быть членом' ExecutionServicesImpl'? – Frans

ответ

1

Я не подозреваю, что OP понравится, так как вы хотите сделать что-то «неправильное», работать «правильно». На самом деле это не так. Всякий раз, когда вы сталкиваетесь с циклической зависимостью, «правильным» решением является рефакторинг для удаления этой зависимости.

В вашем случае, WorkExecutor является синглом, поэтому он, вероятно, должен оставаться как есть. Затем ExecutionServicesImpl необходимо изменить, чтобы удалить зависимость от WorkExecutor. Не зная специфики кода, нельзя сказать слишком много. Тем не менее, наличие ExecutionService будет независимым от его «рабочего», это сокращение связи и, вероятно, очень хорошая вещь в долгосрочной перспективе.

0

Почему ExecutionServicesImpl зависит от WorkExecutor?

Показать больше ядро, ExecutionServices также звучит как Singleton, почему он зависит друг от друга, чтобы работать правильно?

WorkExecutor звучит как-то, что вы можете передать в ExecutionService как WorkExecutor будет закачиваться где-то еще, может быть, тот, который использует Service.

Я не знаю, показать больше кода и, вероятно, это ответ, он выглядит сложным.

0

Я столкнулся с ситуацией в проекте Swing, где сторонний объект зависел от JFrame, а JFrame зависел от стороннего объекта для создания его области содержимого. Я придумал это решение, но в конечном итоге решил закрыть цикл в моем основном методе после построения графа объектов.В принципе, я создал два именованных JFrame поставщиков, второй в зависимости от первого и возвращаясь в тот же экземпляр:

@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; 
} 

Для этого на работу, второй поставщик должен быть использован по крайней мере один раз. Это можно сделать, добавив к первому пакетный частный классификатор, как описано в this answer.

Смежные вопросы