2012-02-20 66 views
7

我想添加一个对象的集合到一个arrayList,只有当这个特定的属性不是null的时候。我应该扩展ArrayList以添加非空的属性吗?

我在考虑扩展ArrayList并在子类中执行检查。

另一种方法是在将属性放入Arraylist之前检查属性,但这意味着,如果需要将对象添加到基于逻辑的阵列列表中,我将不得不分散if检查每个位置。

我想知道你的想法...第二个想法是矫枉过正?

回答

20

Decorator模式

我真的建议使用证据充分的Decorator图案包裹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 

} 

优点:

  • 您仍然可以访问未经验证的原始列表,如果你想要的(但你可以限制这个)
  • 更容易堆叠不同的验证,有选择地打开和关闭它们。
  • 促进composition over inheritance@helios
  • 注意提高可测试性
  • 不配合你到一个特定的List实现,可以添加验证LinkedListHibernate -backed持续名单。你甚至可以考虑通用Collection修饰器来验证任何集合。

实现说明

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

而且你对象必须是不可变的,否则用户可以添加/设置有效的对象并修改它以后违反合同。

良好的面向对象设计

Finaly我写道:

validate(element) 

但考虑:

element.validate() 

这是一个更好的设计。

堆叠验证

如前所述之前,如果你想堆验证,在一个单一的,独立的类验证每个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); 

} 

...和少数实现:

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 
    } 
} 

想,只确认

List<MyBusinessObject> list = new FooValidatingDecorator(rawArrayList); 

想验证这两个酒吧

List<MyBusinessObject> list = 
    new BarValidatingDecorator(new FooValidatingDecorator(rawArrayList)); 
+6

对于继承组合而言+1! – helios 2012-02-20 09:40:41

+0

+1感谢您的详细回复 – Sudhakar 2012-02-20 10:38:49

1

如果您想强制执行此操作,我不明白为什么不这样做(尽管您应该在添加以确保成功时检查add方法的返回值)。

这是摆脱冗余逻辑的一种好方法,它可能会或可能不会在后面的软件迭代中出现。

+0

我同意你的看法,但IMO在从某个列表实现延伸时有一个权衡 - 不可能切换到不同的策略,例如,用LinkedList替换ArrayList。代表团将是另一种选择。 – home 2012-02-20 09:39:11

+0

@home排序,只要接口完全相同或稍微接近,就可以很容易地将一些将arraylist扩展到某些扩展其他东西的东西。 – 2012-02-20 09:40:43

+0

再次同意。 +1 – home 2012-02-20 09:41:49

0

唯一的问题是如果你去重用这段代码,你不记得你已经覆盖了ArrayList类,请确保彻底地评论。

1

我不认为这是一个很好的做法。请考虑在具有两个参数的Util-Class中编写一个Util-Method:您想要添加的数组列表和对象。在那里你可以检查你想要的任何东西,并且可以在你的代码中重复使用逻辑。

相关问题