我应该扩展ArrayList以添加非null的属性吗?

Sud*_*kar 8 java abstraction arraylist reusability

我想将一个对象集合添加到arrayList,只有当特定属性不为null时.

我正在考虑扩展ArrayList并在子类中实现检查.

另一种方法是在将它放入Arraylist之前检查属性,但这意味着,如果我需要根据逻辑将对象添加到arraylist,我必须分散if检查每个位置.

我想知道你对它的看法......再想一想,这是一种矫枉过正吗?

Tom*_*icz 22

装饰图案

我实际上建议ArrayList使用记录良好的Decorator模式进行包装.您只需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

}
Run Code Online (Sandbox Code Playgroud)

好处:

  • 如果需要,您仍然可以访问原始列表而无需验证(但您可以限制此操作)
  • 更容易堆叠不同的验证,有选择地打开和关闭它们.
  • @helios所述,促进组合而不是继承
  • 提高可测试性
  • 不会将您绑定到特定List实现,您可以添加验证LinkedListHibernate -backed持久列表.您甚至可以考虑使用通用Collection装饰器来验证任何集合.

实施说明

尽管实施记得有相当多的方法,你必须要记住,同时覆盖:add(),addAll(),set(),subList()(?),等等.

此外,您的对象必须是不可变的,否则用户可以添加/设置有效对象,然后修改它以违反合同.

良好的OO设计

最后我写道:

validate(element)
Run Code Online (Sandbox Code Playgroud)

但考虑一下:

element.validate()
Run Code Online (Sandbox Code Playgroud)

这是一个更好的设计.

堆叠验证

如前所述,如果要堆叠验证,验证单个独立类中的每个proprty/apsect,请考虑以下习惯用法:

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);

}
Run Code Online (Sandbox Code Playgroud)

......而且实施很少:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

想只验证foo

List<MyBusinessObject> list = new FooValidatingDecorator(rawArrayList);
Run Code Online (Sandbox Code Playgroud)

想验证foobar

List<MyBusinessObject> list = 
  new BarValidatingDecorator(new FooValidatingDecorator(rawArrayList));
Run Code Online (Sandbox Code Playgroud)