Nested Objects Best Practice

醉酒当歌 提交于 2019-12-09 12:14:18

问题


What is the best practice for referencing nested objects?

Say I have the following:

class Outer {
 private InnerA innerA;
 //getters and setters
}

class InnerA {
  private InnerB innerB;
  //getters and setters
}

class InnerB {
  private String someString;
  //getters and setters
}

and in my controller or service class I need to check the someString String variable of the InnerB class to make sure it is not null or not empty so I do this:

if (getOuter().getInnerA().getInnerB().getSomeString() != null && !getOuter().getInnerA().getInnerB().getSomeString().equalsIgnoreCase("") {
  //do something
}

To me this looks messy and could have issues if the nested objects themselves are null.

Do I create getters ans setters in the parent objects for the child objects checking for null? Just wondering what the best practice was if any and/or what some of you do in your code?


回答1:


If any of those objects can be null, then you have to check for null before calling a getter on this object, of course.

But this kind of chaining is a bad smell of a lack of encapsulation (anemic objects having just data, and no behavior). You're violating the law of Demeter : don't talk to strangers.




回答2:


You can use Apache Commons BeanUtils to navigate through your nested properties like this:

Add method getSomeString() to your Outer class and write something like

PropertyUtils.getNestedProperty(this, "innerA.innerB.someString");

I can't remember if that PropertyUtils class check null properties, but I would look Apache Commons BeanUtils site.

Hope this helps!




回答3:


You have two options:

  1. Use Null Object design pattern
  2. Wait for Java 7 Java 8 null safe operator.



回答4:


I would recommend reading up on the Law of Demeter.




回答5:


I don't think users of Outer should have knowledge of Outer.InnerA.InnerB.SomeString - it's buried to deep. You can't change implementation of InnerB without touching clients of Outer 3 levels separated - so what's the point of even having inner classes? Situations like you're describing are ugly and shouldn't arise.

I'd recommend you first consider whether SomeString belongs in InnerB or InnerA or Outer.

Now suppose your hierarchy is correct, yet SomeString has this unique property of being required by clients of Outer (if SomeString is not unique that way, hierarchy is definitely wrong). In this case, Outer.getSomeString(), or better yet, Outer.isSomeStringNullOrEmpty(), so that at least clients of Outer don't have to know about InnerA and InnerB

PS. someString.equalsIgnoreCase("") is expensive, don't use that. Much cheaper is someString.length() == 0




回答6:


It's messy, but if you only had to do it in one place then I might live with it. Otherwise, I'd implement a Outer.getSomeString() that hides the internal path, since your Outer class is the one you're exposing as your interface.

This also allows you to deal with a case where one of the intermediary inner classes is null, without having to do a number of sequential checks each time you try to access someString.




回答7:


My belief is that you should not expose "inner-inner" members through methods of the outer class unless you are adding some sort of functionality or different behaviour to them or the value is "essential" to the use of the outer class. However this is also a matter of judgement and can vary depending on the use and architecture of your code.

On a side note if you want the code for a long string of invocations to be "less ugly" I suggest voting for addition of the Elvis Operator for project coin in the next version of Java (I wish it had made it into 7 :-().




回答8:


This is a java limitation. You should implement helper methods in the parent "OuterObject" if it helps you to reduce code duplication.

This helper methods are useful for object which are aggregating other object and you need to check only if the nested value exists.

Code:

getOuter().hasInnerB();

Which would do all the null checks.

This problem occurs often with objects generated from *.xsd. In a complicated xml structure it happens often that there a many nested optional nodes. And what usually is interesting is the last node. Then its better to write helper methods which will answer the questions if node exists for reuse.

If it comes up to your cod sample i usually write something like that

if (hasSomeString(getOuter())) {
  //do something
}



回答9:


I've written a Java 8 Method:

public class Helper {
    public static <IN, OUT> OUT returnNullOrCallFunction(IN o, Function<IN, OUT> f) {
        return o == null ? null : f.apply(o);
    }
}

Now you can call:

Helper.returnNullOrCallFunction(
        myObject.getSomeOtherObject(),
        SomeOtherObject::toString
);

If myObject.getSomeOtherObject() is null the method will return null, else it will call myObject.getSomeOtherObject().toString().

That's pretty useful, if you just have to go one level deeper.

For multi level, it gets ugly:

Helper.returnNullOrCallFunction(
        Helper.returnNullOrCallFunction(
                myObject.getSomeOtherObject(),
                SomeOtherObject::getAnotherObject
        ),
        AnotherObject::toString
);


来源:https://stackoverflow.com/questions/5248691/nested-objects-best-practice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!