最佳实践:获得对象的深层价值

时间:2014-10-21 15:00:37

标签: java

通常在java中,我必须得到一个对象的属性值,该对象深入此对象。例如,如果我确定我的所有子对象都不为空,我可以这样做:

public function getDeepValue(A a) {

    String value = a.getB().getC().getListeD().get(0).getE().getValue();
    return value;
}

但是如果父对象的子对象可以为null,我必须测试每个对象 为此,我看到了2/3解决方案:

首先,一步一步:

public function getDeepValue(A a) {

    if(a == null){
        return null;
    }

    B b = a.getB();
    if(b == null) {
        return null;
    }

    C c = b.getC();
    if(c == null){
        return null;
    }

    List<D> ds = c.getListeD();
    if(ds == null || ds.size() == 0){
        return null;
    }

    D d = ds.get(0);
    if(d == null) {
        return null;
    }

    E e = d.getE()
    if(e == null){
        return null;
    }

    return e.getValue();
}

其次,如果是块,则测试all in soooo dirty:

public function getDeepValue(A a) {

    if(a != null && a.getB() != null && a.getB().getC() != null && a.getB().getC().getListeD() != null && a.getB().getC().getListeD().size() > 0 && a.getB().getC().getListeD().get(0) != null && a.getB().getC().getListeD().get(0).getE() != null){
        return a.getB().getC().getListeD().get(0).getE().getValue();
    }

    return null;
}

第三种解决方案,使用try catch块:

public function getDeepValue(A a) {

    try {
        return a.getB().getC().getListeD().get(0).getE().getValue();

    } catch(NullPointerException e) {
        return null;

    } catch(IndexOutOfBoundsException e) {
        return null;
    }
}

解决方案1似乎并不太糟糕,但需要大量代码。这通常是我使用的解决方案 解决方案2对我来说真的很脏...
在论文中,我真的很喜欢解决方案3,但它在性能方面是一个很好的解决方案吗?

还有其他人接受解决方案吗? 谢谢你的帮助,我希望我的英语不算太糟糕。
此致

2 个答案:

答案 0 :(得分:1)

解决方案#3看起来很简单,但它可能隐藏一大堆问题。如果您可以完全访问链中的所有类并且您知道每种方法中发生了什么,并且您可以保证这些方法不会成功,那么它可能是一个适当的解决方案导致你的尝试/捕获问题,并且你永远不会改变它们......这使得它成为一个有价值的解决方案有很多条件,但我可以设想它可能是有用的足够的。

解决方案#2看起来很可怕,特别是如果一个或多个get方法是瓶颈(例如慢速数据库查询或使用阻塞网络连接)。链中的早期这样一个潜在的瓶颈,它可能会越糟糕,因为你一遍又一遍地调用它。这当然取决于所讨论方法的实现(例如,即使其中一个方法很慢,结果也可以缓存,但是你不应该 知道你的客户代码。即使使用高效或简单的实现,您仍然需要重复方法调用的开销,这是您不需要的。

解决方案#1是三者中最好的,但它可能不是最好的可能。这个解决方案比其他两个代码占用更多代码,但它不会重复,并且不会被其他方法的实现绊倒。 (注意:如果您无法访问链中的类进行重构,我会使用此解决方案。)

比#1更好的解决方案是重构类,以便客户端代码不需要知道所有。这些方面的东西:

class Client {
    public Mumble getDeepValue(A a) { return a == null ? null : a.getDeepValue(); }
}

class A {
    private B b;
    public Mumble getDeepValue() { return b == null ? null : b.getDeepValue(); }
}

class B {
    private C c;
    public Mumble getDeepValue() { return c == null ? null : c.getDeepValue(); }
}

class C {
    private List<D> ds;
    public Mumble getDeepValue() {
        D d = ds == null || ds.size() == 0 ? null : ds.get(0);
        return d == null ? null : d.getDeepValue();
    }
}

class D {
    private E e;
    public Mumble getDeepValue() { return e == null ? null : e.getMumble(); }
}

class E {
    private Mumble m;
    public Mumble getMumble() { return m; }
}

正如您所看到的,这些类中最长的链是访问作为该类的私有成员的集合的元素的公共成员。 (基本上ds.get(0).getDeepValue())客户端代码不知道兔子洞有多深,只有A暴露了一个返回Mumble的方法。 Client甚至不需要知道类BCDEList存在于任何地方!

此外,如果我从头开始设计这个系统,我会仔细研究是否可以对其进行重组,以使实际的Mumble对象不那么深。如果我可以合理地将Mumble存储在AB中,我建议您这样做。视情况而定,可能无法实现。

答案 1 :(得分:-1)

在性能方面,解决方案3是最好的。另外它很简单易懂,例如查看循环示例:

int[] b = somevalue;
for(int i=0;i<b.length;i++){
  //do something
}

在这种情况下,对于每次迭代,我们执行条件。但是,还有另一种方法,它使用try和catch

int[] b = somevalue;
try{
  for(int i=0;;i++){
    //do something
  }
}catch(IndexOutOfBoundException e){
  // do something
}

在第二个解决方案中,循环一直持续到我们到达循环结束,然后在我们到达数组末尾时抛出IndexOutOfBoundException。这意味着我们不再检查病情。因此更快。