Лучшая практика для вложенных объектов - PullRequest
6 голосов
/ 09 марта 2011

Как лучше всего обращаться к вложенным объектам?

Скажи, что у меня есть следующее:

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

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

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

и в моем контроллере или классе обслуживания мне нужно проверить переменную someString класса InnerB, чтобы убедиться, что она не пуста или не пуста, поэтому я делаю это:

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

Для меня это выглядит грязно и может иметь проблемы, если сами вложенные объекты равны нулю.

Создаю ли я методы получения и установки в родительских объектах для дочерних объектов, проверяющих нулевое значение? Просто интересно, какова была лучшая практика, если таковая имеется, и / или что некоторые из вас делают в своем коде?

Ответы [ 9 ]

8 голосов
/ 09 марта 2011

Если какой-либо из этих объектов может быть нулевым, то вам, конечно, нужно проверить на нулевое значение, прежде чем вызывать геттер для этого объекта.

Но этот вид цепочки является неприятным запахом отсутствия инкапсуляции (анемичные объекты, имеющие только данные и не имеющие поведения).Ты нарушаешь закон Деметры : не разговаривай с незнакомцами.

7 голосов
/ 09 марта 2011

Вы можете использовать Apache Commons BeanUtils для навигации по вашим вложенным свойствам, например:

Добавьте метод getSomeString() в свой Outer класс и напишите что-то вроде

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

Я не могу вспомнить, если бы этот PropertyUtils класс проверял нулевые свойства, но я бы посмотрел Apache Commons BeanUtils site.

Надеюсь, это поможет!

4 голосов
/ 09 марта 2011

Я бы порекомендовал прочесть по Закону Деметры .

4 голосов
/ 09 марта 2011

У вас есть два варианта:

  1. Использование Шаблон проектирования пустых объектов
  2. Ожидание Java 7 Java 8 нулевой безопасный оператор.
1 голос
/ 20 марта 2015

Это ограничение Java.Вы должны реализовать вспомогательные методы в родительском «OuterObject», если это поможет вам уменьшить дублирование кода.

Эти вспомогательные методы полезны для объекта, который агрегирует другой объект, и вам нужно проверять только наличие вложенного значения.

Код:

getOuter().hasInnerB();

, который будет выполнять все проверки на ноль.

Эта проблема часто возникает с объектами, сгенерированными из * .xsd.В сложной структуре XML часто бывает много вложенных дополнительных узлов.И что обычно интересно, так это последний узел.Тогда лучше написать вспомогательные методы, которые ответят на вопросы, если узел существует для повторного использования.

Если дело доходит до вашего примера трески, я обычно пишу что-то подобное

if (hasSomeString(getOuter())) {
  //do something
}
1 голос
/ 09 марта 2011

Я считаю, что вам не следует открывать «внутренние-внутренние» члены с помощью методов внешнего класса, если вы не добавляете к ним какую-либо функциональность или другое поведение, или значение «существенно» для использования внешнего класса , Однако это также вопрос оценки и может варьироваться в зависимости от использования и архитектуры вашего кода.

На заметку, если вы хотите, чтобы код для длинной строки вызовов был "менее уродливым", я предлагаю проголосовать за добавление оператора Элвиса для монеты проекта в следующей версии Java (я жаль, что это не превратилось в 7: - ().

1 голос
/ 09 марта 2011

Это грязно, но если бы вам пришлось сделать это только в одном месте, я бы с этим смирился.В противном случае я бы реализовал Outer.getSomeString(), который скрывает внутренний путь, поскольку ваш Outer-класс - это тот, который вы выставляете в качестве интерфейса.

Это также позволяет вам иметь дело со случаем, когда один изпромежуточные внутренние классы равны нулю, без необходимости выполнять ряд последовательных проверок каждый раз, когда вы пытаетесь получить доступ к someString.

1 голос
/ 09 марта 2011

Я не думаю, что пользователи Outer должны знать Outer.InnerA.InnerB.SomeString - он похоронен глубоко. Вы не можете изменить реализацию InnerB, не затрагивая клиентов с разделенными внешними уровнями 3 - так какой смысл даже иметь внутренние классы? Ситуации, которые вы описываете, ужасны и не должны возникать.

Я бы порекомендовал вам сначала подумать, принадлежит ли SomeString к InnerB или InnerA или Outer.

Теперь предположим, что ваша иерархия верна, но SomeString обладает этим уникальным свойством, которое требуется клиентам Outer (если SomeString не уникален в этом смысле, иерархия определенно неверна). В этом случае Outer.getSomeString () или, еще лучше, Outer.isSomeStringNullOrEmpty (), так что по крайней мере клиенты Outer не должны знать о InnerA и InnerB

PS. someString.equalsIgnoreCase ("") стоит дорого, не используйте это. Гораздо дешевле - someString.length () == 0

0 голосов
/ 17 октября 2014

Я написал метод Java 8:

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

Теперь вы можете вызывать:

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

Если myObject.getSomeOtherObject() равно null, метод вернет nullв противном случае он будет вызывать myObject.getSomeOtherObject().toString().

Это очень полезно, если вам просто нужно пройти на один уровень глубже.

Для многоуровневого уровня это выглядит ужасно:

Helper.returnNullOrCallFunction(
        Helper.returnNullOrCallFunction(
                myObject.getSomeOtherObject(),
                SomeOtherObject::getAnotherObject
        ),
        AnotherObject::toString
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...