Я не могу найти оптимальный подход к решению следующей проблемы. Скажем, есть абстрактный базовый класс с несколькими конкретными подклассами:Избегайте литье типа во время обработки данных
public abstract class AbstractType { /* common properties */ }
public class TypeA { /* properties of type A */ }
public class TypeB { /* properties of type A */ }`
Эти классы домена (JPA лица). Свойства типов (среди прочего) используются для проверки пользовательских данных. Я полагаю, что добавление логики к самой модели домена считается плохой практикой. Поэтому я хочу избежать добавления метода validate
к конкретным подклассам. Как так:
UserInput userInput = ...;
AbstractType data = ...;
data.validate(userInput);
Я не вижу вариант без необходимости отливать модель предметной области, , если я хочу, чтобы переместить логику к логическому слою. Имея ограниченные знания, я могу только придумать два похожих «решения», используя какой-то интерфейс обработчика.
Держите некоторую прямую ссылку на обработчик в типе
public interface TypeHandler { public validate(AbstractType data, UserInput userInput); } /* TypeAHandler & TypeBHandler implementations */ public enum Type { TYPE_A(new TypeAHandler()), TYPE_B(new TypeBHandler()); private TypeHandler handler; public Handler(TypeHandler handler){ this.handler = handler; } public TypeHandler getHandler(){ return handler; } } public class TypeA { private Type type = TYPE_A; /* ... */ }
Обработчик бы, чем можно назвать следующим образом:
UserInput userInput = ...; AbstractType data = ...; data.getType.getHandler().validate(data, userInput);
Ссылка на обработчик также может быть добавлен сразу (без переименования между ними) как свойство класса AbstractType, но это будет означать, что есть ссылка на класс внутри логического уровня из модели домена (какой тип o f побеждает цель перемещения логики на логический уровень?)
Проблема здесь также в том, что метод проверки внутри TypeXHandler должен передать аргумент
data
в свой подкласс прежде, чем он сможет начать проверку.Или я мог бы реализовать некоторый метод, который имеет большую структуру if-then, чтобы получить правильный подкласс, бросить его и вызвать соответствующий обработчик, который реализует интерфейс, подобный следующему.
public interface TypeHandler<T extends AbstractType> { public validate(T data, UserInput userInput); }
Таким образом, в обоих случаях есть литье. В первом случае нет огромной if-then структуры, но логика и домен не разделены. Во втором случае существует очень негибкая структура if-then.
В заключение, вот мой вопрос. Должен ли я действительно избегать реализации логики непосредственно внутри домена? Если да, есть ли способ избежать кастинга, структуры if-else и/или добавления дополнительных свойств в модель домена (например, перечисление в первом «решении»).
Спасибо @Ий за ответ. Мне очень нравится параграф с объяснением дженериков! Помогает мне вставить дженерики в перспективу. Отражение действительно могло помочь в решении проблемы, но я думаю, что это слишком далеко, чтобы избежать логики в сущности. – badoit
Вы считаете, что композиция здесь будет хорошей подгонке?Имея класс 'Data' со свойствами' TypeA typeAcontent' и 'TypeB typeBcontent' и передавая экземпляр' Data' методу 'оценки' правой реализации IValidator'? Может ли это стать беспорядочным, если число конкретных классов увеличивается? (мне кажется, что это будет самый чистый вариант) – badoit
Я думаю, что это зависит от ваших потребностей в расширении - сколько из этих реализаций AbstractType вы будете иметь, изменится ли это в будущем и т. д. Мне конечная разница заключается в том, будете ли вы проверять типы в каком-то центральном месте (менее расширяемы, но могут быть не такими плохими для небольшого числа типов) или с использованием полиморфизма. –