Короткий ответ: Да, именно здесь вы начинаете, но это не обязательно хорошая конечная точка. TopClass должен заботиться только о (интерфейсах) A
, B
и AB
. Реализации и зависимости этих объектов не относятся к TopClass. Это также означает, что высмеивание TopClass должно быть очень простым: вам нужен макет A, макет B и макет AB, и вы можете передать их напрямую.
Как вы создаете A
без забот о зависимостях A
? Вместо экземпляра A
получите Provider<A>
, где Provider - это встроенный интерфейс без аргумента Java.
В этот момент ваши конструкторы выглядят следующим образом:
TopClass(A a, B b, AB ab)
A(A1 a1, A2 a2, A3 a3, A4 a4, AB ab)
B(B1 b1, AB ab)
Если какой-либо из этих типов может быть заменен Provider<Type>
, если вы хотите отложить создание до тех пор, пока это необходимо, или если вам нужно больше, чем один ,
«Но подождите!» Я слышу, как ты плачешь. «Разве это не значит, что я должен сделать сложную серию поставщиков шаблонов, чтобы скрыть детали реализации/зависимости от TopClass?» Да, это так, и вы можете сделать это вручную - или вы можете использовать инфраструктуру инъекции зависимостей, такую как Spring, Guice или Dagger.
Руководство один будет выглядеть примерно так:
public class EntryPoint() {
AB ab = new AB();
Provider<TopClass> provideTopClass() {
return new Provider<TopClass>() {
@Override public TopClass get() {
return new TopClass(provideA().get(), provideB().get(), provideAB().get());
}
};
}
Provider<A> provideA() {
return new Provider<AB>() {
@Override public AB get() {
return new A(provideA1().get(), provideA2.get(), ...);
}
};
}
Provider<AB> provideAB() {
return new Provider<AB>() {
@Override public AB get() {
return ab; // always reuse the same instance if you'd like
}
};
}
// and so forth
}
Там, вы только что извлеченный все создания и проводки в один класс, который Guice может эмулировать во время выполнения и которые Dagger может генерировать непосредственно во время компиляции. Вам нужно будет работать с вашей командой, чтобы выбрать структуру, которую вы хотите, или начать вручную, но в целом это должно обеспечить много вознаграждений в создании легко собираемого и простого в использовании приложения.
Одно небольшое примечание: не просто механически инвертируйте зависимость каждого класса, который используется внутри. Существует различие, называемое [peers vs. internals] (https://groups.google.com/forum/#!topic/growing-object-oriented-software/U_8PsEOwT5k): если какой-либо объект является одноранговым, то можно запросить зависимости, например, посредством инъекции конструктора. Если объект является «внутренней» деталью реализации, которая не использует ничего, что делает ваш код трудным для тестирования, вы можете решить, что его не стоит вводить и просто продолжать создавать его в самом TopClass. – prgmtc