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