Вопрос
Как лучше всего я могу управлять построением графа объектов, где требуется сложная логика проверки?. Я хотел бы сохранить зависимые инъецированные конструкторы do-nothing для целей проверки.
Testability очень важна для меня, что делает ваше предложение для поддержания этого атрибута кода?
Фон
У меня есть объект plain-old-java-object, который управляет структурой некоторых бизнес-данных для меня:
class Pojo
{
protected final String p;
public Pojo(String p) {
this.p = p;
}
}
Я хочу убедиться, что p имеет допустимый формат, потому что этот бизнес-объект действительно не имеет смысла без этой гарантии; его даже не нужно создавать, если р - бессмыслица. Однако проверка p не является тривиальной.
Catch
Действительно, для этого требуется достаточно сложная логика проверки, что логика должна быть полностью проверена в ней собственными правами, и поэтому у меня есть эта логика в отдельном классе:
final class BusinessLogic() implements Validator<String>
{
public String validate(String p) throws InvalidFoo, InvalidBar {
...
}
}
Возможные повторяющиеся вопросы
- Где должна быть реализована логика проверки? - принятый ответ непроницаем для меня. Я прочитал "быть запущенным в родной среде класса" в качестве тавтологии, как правила проверки могут выполняться в чем-либо, кроме "родной среды класса"? Точка 2 я не могу заглянуть, поэтому я не могу комментировать.
- Где предоставить логические правила для проверки? - Оба ответа предполагают, что ответственность лежит на поставщике клиент/данные, который мне нравится в принципе. Однако в моем случае клиент может не быть инициатором данных и не может его проверить.
- Где сохранить логику проверки? - предполагает, что проверка может принадлежать модели, однако я считаю этот подход менее идеальным для тестирования. В частности, для каждого unit test мне нужно заботиться обо всей логике проверки даже во время тестирования других частей модели - я никогда не могу полностью изолировать то, что я хочу проверить, следуя предложенному подходу.
Мое мышление до сих пор
Хотя следующий конструктор открыто объявляет зависимости Pojo и сохраняет свою простоту проверки, он совершенно небезопасен. Здесь нет ничего, что помешало бы клиенту предоставить валидатор, который утверждает, что каждый вход является приемлемым!
public Pojo(Validator businessLogic, String p) throws InvalidFoo, InvalidBar {
this.p = businessLogic.validate(p);
}
Итак, я немного ограничиваю видимость конструктора, и я предоставляю метод factory, который обеспечивает проверку, а затем конструкцию:
@VisibleForTesting
Pojo(String p) {
this.p = p;
}
public static Pojo createPojo(String p) throws InvalidFoo, InvalidBar {
Validator businessLogic = new BusinessLogic();
businessLogic.validate(p);
return new Pojo(p);
}
Теперь я мог бы реорганизовать createPojo в класс factory, который восстановит "единую ответственность" для Pojo и упростит тестирование логики factory, не говоря уже о преимуществах производительности, которые больше не расточительно создают новый (без гражданства) BusinessLogic для каждого нового Pojo.
Мне кажется, что я должен остановиться, попросить внешнее мнение. Я на правильном пути?