Закон Деметры IntelliJ Идеи. Ложный позитив или нет?

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

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() из того же класса!

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

Спасибо.

2 ответа

Решение

Технически, это нарушает законы Деметры. Хотя я бы поспорил, что частные функции должны рассматриваться для LoD-F, так как предположительно они недоступны извне. В то же время, это не нарушает законы Деметры, если "вещь" принадлежит Test. Но в 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 состоит в том, чтобы производить или выставлять вещи, а не быть посредником в манипулировании вещами.

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), единственное решение - отключить его и попытаться избежать этих ситуаций вручную.

Другие вопросы по тегам