У меня есть некоторый код, который похож:
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 (), и сохранить мои собственные ссылки на эти объекты?
По моему опыту, выполнение того, что вы предлагаете (сделайте так, чтобы все методы вызывали только «следующий уровень»), поможет выявить изменения в вашем API, которые вы должны внести. Итак, да, внесите эти изменения, несмотря на то, что они загромождают ваш API, и вы можете найти подходящий способ решения проблем.
«Факт» состоит в том, что у чего-то есть Клиент, тогда как у чего-то есть (или он хочет иметь) что-то еще. Это означает, что либо функциональность этого другого объекта находится не в том месте, либо объект, запрашивающий эту функциональность, находится не в том месте. К сожалению, сложно привести конкретные примеры без более полного кода.
Однако, когда вы наконец поймете, в чем заключаются «проблемы», решения могут оказаться не такими легкими для реализации. Это облом, но все равно продолжайте в том же духе и реорганизуйте это решение!
Кто получает доступ к Client
? Нужно ли вам держать его родительский
в закрытом доступе, или вы должны раскрыть его, чтобы вызывающий код мог перейти к нужным функциям?
Если вы беспокоитесь о полном раскрытии родительского
, другой вариант - извлечь интерфейс из родительского
и раскрыть его из клиентского
.
Это не совсем Feature Envy, а скорее проблема высокой связи между этими классами и определенное нарушение закона Деметры http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/general-formulation.html. Ваша первая мысль о том, что методы должны быть непосредственно в родительском классе, хороша. Клиенты не должны вызывать методы через стек.
Если вы беспокоитесь о том, что родитель слишком занят, возможно, у вас слишком много функциональности, и ее следует разделить на несколько меньших классов. Классы должны быть одноцелевыми.