Простой (и длительный) вопрос, а не простой ответ. Работая с некоторыми рамками DI (Spring, Guice), я пришел к выводу, что некоторые из практик, представленные другими, не так просто реализовать. На самом деле я действительно застрял на этом уровне.Зависимость от впрыска, замедленная инъекция praxis
Я постараюсь представить это как можно более простым, хотя некоторые детали, вероятно, будут потеряны. Надеюсь, этот вопрос будет ясен.
Скажем, у меня есть StringValidator, простой класс с ответственностью за проверку строк.
package test;
import java.util.ArrayList;
import java.util.List;
public class StringValidator {
private final List<String> stringList;
private final List<String> validationList;
private final List<String> validatedList = new ArrayList<String>();
public StringValidator(final List<String> stringList, final List<String> validationList) {
this.stringList = stringList;
this.validationList = validationList;
}
public void validate() {
for (String currentString : stringList) {
for (String currentValidation : validationList) {
if (currentString.equalsIgnoreCase(currentValidation)) {
validatedList.add(currentString);
}
}
}
}
public List<String> getValidatedList() {
return validatedList;
}
}
Зависимость является минимально возможной, что позволяет простые тесты, подобные этим:
package test;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class StringValidatorTest {
@Test
public void testValidate() throws Exception {
//Before
List<String> stringList = new ArrayList<String>();
stringList.add("FILE1.txt");
stringList.add("FILE2.txt");
final List<String> validationList = new ArrayList<String>();
validationList.add("FILE1.txt");
validationList.add("FILE20.txt");
final StringValidator stringValidator = new StringValidator(stringList, validationList);
//When
stringValidator.validate();
//Then
Assert.assertEquals(1, stringValidator.getValidatedList().size());
Assert.assertEquals("FILE1.txt", stringValidator.getValidatedList().get(0));
}
}
Если мы хотим, чтобы увеличить гибкость даже больше, мы могли бы использовать коллекцию <> вместо списка <>, но давайте предположим, что это не понадобится.
Классов, которые создают списки являются следующими (использовать любой другой стандартный интерфейс):
package test;
import java.util.List;
public interface Stringable {
List<String> getStringList();
}
package test;
import java.util.ArrayList;
import java.util.List;
public class StringService implements Stringable {
private List<String> stringList = new ArrayList<String>();
public StringService() {
createList();
}
//Simplified
private void createList() {
stringList.add("FILE1.txt");
stringList.add("FILE1.dat");
stringList.add("FILE1.pdf");
stringList.add("FILE1.rdf");
}
@Override
public List<String> getStringList() {
return stringList;
}
}
И:
package test;
import java.util.List;
public interface Validateable {
List<String> getValidationList();
}
package test;
import java.util.ArrayList;
import java.util.List;
public class ValidationService implements Validateable {
private final List<String> validationList = new ArrayList<String>();
public ValidationService() {
createList();
}
//Simplified...
private void createList() {
validationList.add("FILE1.txt");
validationList.add("FILE2.txt");
validationList.add("FILE3.txt");
validationList.add("FILE4.txt");
}
@Override
public List<String> getValidationList() {
return validationList;
}
}
И у нас есть основной класс с основным методом:
package test;
import java.util.List;
public class Main {
public static void main(String[] args) {
Validateable validateable = new ValidationService();
final List<String> validationList = validateable.getValidationList();
Stringable stringable = new StringService();
final List<String> stringList = stringable.getStringList();
//DI
StringValidator stringValidator = new StringValidator(stringList, validationList);
stringValidator.validate();
//Result list
final List<String> validatedList = stringValidator.getValidatedList();
}
}
Итак, предположим, что классы генерируют списки во время выполнения (когда пользователь хочет). «Прямая» (статическая) привязка невозможна.
Если мы хотим обеспечить минимально возможную связь, мы будем использовать списки, чтобы предоставить нам данные, необходимые для выполнения проверки (StringValidator).
НО, если мы хотим использовать контейнер, чтобы помочь нам с «кодом клея», мы могли бы ввести две «службы» в StringValidator. Это предоставит нам правильные данные, но за счет СОЕДИНЕНИЯ. Кроме того, StringValidator будет нести дополнительную ответственность за фактическое обращение к зависимостям.
Если я использую делегацию таким образом, я помешаю своему коду нежелательными обязанностями (не то, что я хочу).
Если я этого не сделаю, я не вижу способа, которым это могло бы работать (провайдер может предоставить мне правильные списки, но опять же, зависимость там).
Более общий вопрос: существует ли способ создать полностью развязанное приложение с использованием каркасов DI или это какой-то идеал? В каких ситуациях вы используете рамки DI, в которых вы этого не делаете? Являются ли рамки DI действительно «новыми новыми»?
спасибо.
Нет, я имел в виду использование рамки DI для кода «клей» - архитектурный код и удаление любых очевидных прямых зависимостей для достижения большей гибкости. Должны быть зависимости, но скрыты внутри контейнера. Извините, если это несколько абстрактно, но для того, чтобы действительно задать правильный вопрос с конкретным примером - это займет страницы. – pfh