Закон IntelliJ Idea инспекции Деметры. Ложноположительный или нет?

Предположим, что следующий класс

interface Thing {
  void doSomething();
}

public class Test {
  public void doWork() {
    //Do smart things here
    ...
    doSomethingToThing(index);
    // calls to doSomethingToThing might happen in various places across the class.
  }

  private Thing getThing(int index) {
    //find the correct thing
    ...
    return new ThingImpl();
  }

  private void doSomethingToThing(int index) {
    getThing(index).doSomething();
  }      
}

Intelli-J сообщает мне, что я нарушаю закон деметра, поскольку DoSomethingToThing использует результат функции, и якобы вы можете вызывать только методы полей, параметров или самого объекта.

Неужели мне нужно делать что-то вроде этого:

public class Test {
  //Previous methods
  ...

  private void doSomething(Thing thing) {
    thing.doSomething();
  }

  private void doSomethingToThing(int index) {
    doSomething(getThing(index));
  }
}

Я считаю это обременительным. Я думаю, что закон Деметры таков, что один класс не знает внутренней части ДРУГОГО класса, но getThing() принадлежит к тому же классу!

Это действительно нарушение закона Деметры? это действительно улучшает дизайн?

Спасибо.


person superjugy    schedule 23.10.2013    source источник


Ответы (2)


Технически это нарушает законы Деметры. Хотя я бы поспорил с тем, что для LoD-F следует рассматривать частные функции, поскольку якобы они недоступны извне. В то же время, это не нарушение законов Деметры, если «вещь» принадлежит Тесту. Но в Java единственный способ добраться до объекта может быть через геттер, который возвращает это к технической стороне дела (нет четкого разделения между методами получения и действия).

Я бы сказал, сделайте это:

public class Test {
  private Thing getThing(int index) {
    //find the thing
    return thing;
  }

  private void DoSomethingToThing(Thing thing) {
    thing.doSomething();
  }

  private void DoSomethingToThing(int index) {
    DoSomethingToThing(getThing(index));
  }
}

Или, возможно, лучше, чтобы вызывающий абонент использовал вещь напрямую. Что возможно, если функция Test состоит в том, чтобы производить или обнажать вещи, а не быть посредником для манипулирования вещами.

person Pawel Veselov    schedule 23.10.2013
comment
Что вы имеете в виду, что Thing предоставляет методы, которые с ним что-то делают? поскольку Вещь разоблачает doSomething(). В остальном, похоже, вы предлагаете мне добавить дополнительный метод. Верно? - person superjugy; 23.10.2013
comment
Извините, исправлено. Я предлагаю прямую манипуляцию и / или перегрузку, чтобы это выглядело более аккуратно. - person Pawel Veselov; 23.10.2013
comment
Дело в том, что Thing на самом деле является интерфейсом, а getThing создает экземпляр реального класса. но Вещь используется только внутри Test в частном порядке. Я обновлю вопрос, пытаясь отразить это. - person superjugy; 23.10.2013
comment
Тогда вы можете признать, что функция Test заключается в создании / хранении / предоставлении экземпляров Thing и ничего больше. - person Pawel Veselov; 24.10.2013
comment
Что ж, у него есть эта функция, но есть и другие функции. Вы можете понять, что это, вероятно, должно быть два класса вместо одного. Это звучит интересно. Я займусь этим. Я приму твой ответ сейчас. Большое тебе спасибо. - person superjugy; 24.10.2013

IntelliJ неправильно определяет создание объекта.

Википедия (на которую ссылается IDEA) описывает, что вы можете вызывать объекты, созданные в текущем контексте.

Я так и делаю, но по-прежнему получаю предупреждение на getMajor():

Version version = Loader.readVersion(inputStream); // Instantiates a new Version

if (version.getMajor() != 2)
    throw new IOException("Only major version 2 is supported");

Проверка IDEA предлагает возможность игнорировать вызовы «библиотечных» методов. В моем случае Loader.readVersion() является библиотечным методом, однако он находится внутри текущего проекта (проект должен быть самоподдерживающимся). IDEA считает, что это не библиотечный метод.

Поскольку механизм этой проверки является неадекватным / неполным / наивным (как, кстати, с МНОГИМИ проверками IDEA), единственное решение - отключить его и попытаться избежать подобных ситуаций вручную.

person Mark Jeronimus    schedule 10.08.2016
comment
Что ж, в моем примере экземпляр создавался и использовался в том же классе. В вашем случае вы создаете экземпляр вне класса. Но я согласен. Кроме того, если вы хотите использовать какой-либо инжектор зависимостей, это всегда будет происходить, поскольку инжектор предоставит вам созданный экземпляр объекта, который вам нужен. В итоге я отключил эту проверку. - person superjugy; 12.08.2016