Как я исправляю зависть функции в этом случае?

У меня есть некоторый код, который похож:

class Parent {
 private Intermediate intermediateContainer;
 public Intermediate getIntermediate();
}

class Intermediate {
 private Child child;
 public Child getChild() {...}
 public void intermediateOp();
}

class Child {
 public void something();
 public void somethingElse();
}

class Client {
 private Parent parent;

 public void something() {
  parent.getIntermediate().getChild().something();
 }

 public void somethingElse() {
  parent.getIntermediate().getChild().somethingElse();
 }

 public void intermediate() {
  parent.getIntermediate().intermediateOp();
 }
}

Я понимаю, что это - пример "запаха кода" зависти функции. Вопрос, что лучший способ состоит в том, чтобы зафиксировать его? Мой первый инстинкт должен поместить эти три метода на родителя:

parent.something();
parent.somethingElse();
parent.intermediateOp();

... но я чувствую, что это копирует код и создает помехи API Родительского класса (который уже довольно занят).

Я хочу сохранить результат getIntermediate (), и/или getChild (), и сохранить мои собственные ссылки на эти объекты?

5
задан Mogsdad 27 September 2015 в 02:13
поделиться

3 ответа

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

«Факт» состоит в том, что у чего-то есть Клиент, тогда как у чего-то есть (или он хочет иметь) что-то еще. Это означает, что либо функциональность этого другого объекта находится не в том месте, либо объект, запрашивающий эту функциональность, находится не в том месте. К сожалению, сложно привести конкретные примеры без более полного кода.

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

5
ответ дан 18 December 2019 в 09:05
поделиться

Кто получает доступ к Client? Нужно ли вам держать его родительский в закрытом доступе, или вы должны раскрыть его, чтобы вызывающий код мог перейти к нужным функциям?

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

3
ответ дан 18 December 2019 в 09:05
поделиться

Это не совсем Feature Envy, а скорее проблема высокой связи между этими классами и определенное нарушение закона Деметры http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/general-formulation.html. Ваша первая мысль о том, что методы должны быть непосредственно в родительском классе, хороша. Клиенты не должны вызывать методы через стек.

Если вы беспокоитесь о том, что родитель слишком занят, возможно, у вас слишком много функциональности, и ее следует разделить на несколько меньших классов. Классы должны быть одноцелевыми.

10
ответ дан 18 December 2019 в 09:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: