装饰者模式
我实际上建议包装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
or 休眠-支持的持久列表。你甚至可以考虑通用的Collection
装饰器来验证任何集合。
实施说明
尽管实现了,但请记住,在重写时您必须记住很多方法:add()
, addAll()
, set()
, subList()
(?), ETC。
此外,您的对象必须是不可变的,否则用户可以添加/设置有效对象并随后修改它以违反合同。
良好的面向对象设计
最后我写道:
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 and bar?
List<MyBusinessObject> list =
new BarValidatingDecorator(new FooValidatingDecorator(rawArrayList));