Шаблон декоратора
Я бы действительно рекомендовал обернуть ArrayList
, используя хорошо документированный Декоратор . Вы просто заключаете в ArrayList
другую реализацию List
, которая делегирует большинство методов, но добавляет логику проверки:
public class ValidatingListDecorator extends AbstractList<MyBusinessObject>
{
private final List<MyBusinessObject> target;
public ValidatingListDecorator(List<MyBusinessObject> target) {
this.target = target;
}
@Override
public MyBusinessObject set(int index, MyBusinessObject element)
{
validate(element);
return target.set(index, element);
}
@Override
public boolean add(MyBusinessObject o)
{
validate(o);
return target.add(o);
}
//few more to implement
}
Преимущества:
- При желании вы все равно можете получить доступ к необработанному списку без проверки (но вы можете ограничить это)
- Проще складывать разные проверки, выборочно включать и выключать их.
- Способствует составлению по наследству , как отмечено @ helios
- Улучшает тестируемость
- Не привязывает вас к конкретной реализации
List
, вы можете добавить проверку в LinkedList
или Hibernate постоянные списки. Вы даже можете подумать о универсальном Collection
декораторе для проверки любой коллекции.
Замечания по реализации
Несмотря на реализацию, помните, что при переопределении нужно помнить множество методов: add()
, addAll()
, set()
, subList()
(?) И т. Д.
Также ваш объект должен быть неизменным, в противном случае пользователь может добавить / установить действительный объект и впоследствии изменить его, чтобы нарушить договор.
Хороший ОО дизайн
Наконец я написал:
validate(element)
но учтите:
element.validate()
что лучше дизайн.
Проверка стека
Как отмечалось ранее, если вы хотите объединить валидацию, валидацию каждого свойства / объекта в одном отдельном классе, рассмотрите следующую идиому:
public abstract class ValidatingListDecorator extends AbstractList<MyBusinessObject>
{
private final List<MyBusinessObject> target;
public ValidatingListDecorator(List<MyBusinessObject> target) {
this.target = target;
}
@Override
public MyBusinessObject set(int index, MyBusinessObject element)
{
validate(element);
return target.set(index, element);
}
protected abstract void validate(MyBusinessObject element);
}
... и несколько реализаций:
class FooValidatingDecorator extends ValidatingListDecorator {
public FooValidatingDecorator(List<MyBusinessObject> target)
{
super(target);
}
@Override
protected void validate(MyBusinessObject element)
{
//throw if "foo" not met
}
}
class BarValidatingDecorator extends ValidatingListDecorator {
public BarValidatingDecorator(List<MyBusinessObject> target)
{
super(target);
}
@Override
protected void validate(MyBusinessObject element)
{
//throw if "bar" not met
}
}
Хотите проверить только foo ?
List<MyBusinessObject> list = new FooValidatingDecorator(rawArrayList);
Хотите проверить foo и bar ?
List<MyBusinessObject> list =
new BarValidatingDecorator(new FooValidatingDecorator(rawArrayList));