Чтобы подготовить почву, я пытаюсь сделать чистую инъекцию зависимостей для библиотеки Java, которую я создаю, чтобы сделать ее более тестируемой. Поскольку это библиотека, я хочу сделать чистую инъекцию зависимостей без создания корня контейнера/композиции DI, как это обсуждалось Марком Симаном в его сообщениях в блоге*. Проблема, с которой я сталкиваюсь, заключается в том, что у меня есть несколько классов посетителей, которые должны содержать состояние (пример, иллюстрирующий концепцию, приведен ниже). Было бы чище ввести их или просто объявить их с помощью нового ключевого слова? Единственная проблема, которую я вижу при их внедрении, заключается в том, что мне понадобится функция для очистки состояния посетителя после каждого вызова, а не с использованием нового, в котором я бы не нуждался. Есть ли лучшая практика для этого?
public class CarServiceBuilder {
public CarService buildCarService(){
CarPartPrinter carPartPrinter = new CatPartPrinter();
CarService carService = new CarService(carPartPrinter);
return carService;
}
}
public class CarService {
private final CarPartPrinter printParts;
public CarService(CarPartPrinter carPartPrinter){
this.carPartPrinter = carPartPrinter;
}
public void printParts(Car car){
CarVisitor carVisitor = new CarVisitor();
car.accept(carVisitor);
List<Part> parts = carVisitor.getParts();
carPartPrinter.printParts(parts);
}
}
public class CarVisitor extends Visitor {
private List<Parts> parts;
public CarVisitor(){
parts = new ArrayList<>();
}
@Override
public void visit(Part part){
parts.add(part);
}
}
ПРОТИВ.
public class CarServiceBuilder {
public CarService buildCarService(){
CarVisitor carVisitor = new CarVisitor();
CarPartPrinter carPartPrinter = new CatPartPrinter();
CarService carService = new CarService(carVisitor, carPartPrinter);
return carService;
}
}
public class CarService {
private final CarVisitor carVisitor;
private final CarPartPrinter printParts;
public CarService(CarVisitor carVisitor, CarPartPrinter carPartPrinter){
this.carVisitor = carVisitor;
this.carPartPrinter = carPartPrinter;
}
public void printParts(Car car){
car.accept(carVisitor);
List<Part> parts = carVisitor.getParts();
carPartPrinter.printParts(parts);
carVisitor.clearState();
}
}
public class CarVisitor extends Visitor {
private List<Parts> parts;
public CarVisitor(){
parts = new ArrayList<>();
}
@Override
public void visit(Part part){
parts.add(part);
}
public void clearState(){
parts = new ArrayList<>();
}
}
Связанные записи в блоге:
printParts
знает, что ему нужен CarVisitor
для сбора списка частей), поэтому проще всего просто создать новый локальный экземпляр и выбросьте его, как только вы закончите. Внедрение объектов с состоянием создает проблемы, подобные той, которую вы уже отметили: вам нужно помнить об очистке состояния после того, как вы закончите, и это не является потокобезопасным.
Что касается тестирования, я бы просто рассматривал посетителя как деталь реализации CarService
и напрямую тестировал функциональные требования, то есть действительно ли printParts
печатает правильные части, независимо от того, как это реализовано.