Как слишком много переменных экземпляра приводит к дублированию кода?

19

Согласно рефакторингу по шаблонам :

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

Как слишком много переменных экземпляра приводит к дублированию кода?

q126y
источник
2
Проще говоря: nбулевы переменные, например, создают внутреннее пространство состояний 2^n. Чаще всего ваш объект не имеет такого количества наблюдаемых состояний , но поскольку вы собрали все это состояние в один объект, внутренне вам все равно придется обрабатывать их все.
Бизиклоп

Ответы:

23

Наличие слишком большого количества переменных экземпляра не имеет прямого отношения к дублирующему коду или наоборот. Это утверждение в этой общности ложно. Можно добавить два отдельных класса без дублирующегося кода в один класс - это создает новый класс с неразделенными обязанностями и слишком большим количеством переменных экземпляра, но все еще без дублирующего кода.

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

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

Док Браун
источник
11

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

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

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

Есть по крайней мере одно исключение, которое не попадает в эту категорию и является простым способом исправить это. Immutableу объектов нет этой проблемы, потому что они являются фиксированным состоянием, нет никаких шансов для запутанного управления состоянием или побочных эффектов.


источник
7

Цитируемое вами утверждение должно рассматриваться в определенном контексте.

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

http://c2.com/cgi/wiki?CodeSmell

Забавно, вы обнаружите, что «слишком много переменных экземпляра» так же хорошо пахнут в коде, как и «слишком мало переменных экземпляра».

Но есть проблемы с переменными экземпляра, будь то слишком мало или слишком много:

  1. Каждая переменная экземпляра может означать какой-то статус объекта. Стати всегда нужно бережное отношение. Вы должны убедиться, что вы охватили все возможные комбинации состояний, чтобы избежать неожиданного поведения. Вы должны всегда ясно сейчас: какой статус у моего объекта сейчас? С этой точки зрения многие переменные экземпляра могут указывать на то, что класс стал неуправляемым. Это также может указывать на то, что класс выполняет слишком много заданий, так как ему нужно столько времени.

  2. Каждая переменная экземпляра требует от вас контроля, какие методы изменяют переменную и каким образом. Итак, вдруг вы уже не знаете всех поваров, которые готовят. Один из них, устало запрограммированный поздно ночью, испортит ваш суп. Опять же: слишком много таких переменных приведет к трудностям проникновения в код.

  3. С другой стороны: слишком мало переменных экземпляра может привести к тому, что многие методы должны обрабатывать свою информацию с чрезмерной нагрузкой и слишком большим количеством параметров. Вы чувствуете это, если вы даете многим своим методам определенный равный параметр, и все методы делают что-то очень похожее с этим параметром. В этой ситуации ваш код начнет раздуваться. Вы закончите прокруткой многих экранов вверх и вниз, чтобы собрать вместе несколько простых вещей. Здесь может помочь рефакторинг: ввести одну переменную экземпляра и один четкий вход в нее. Тогда освободите все методы.

  4. Последнее, но не менее важное: если многие переменные экземпляра класса имеют свои методы установки и получения, то это может указывать на то, что другие классы не используют этот первый класс правильно. Существует дискуссия на тему « Почему добытчики и сеттеры злые ». Идея вкратце заключается в том, что если класс Rectangleпредлагает некоторые из них getX()и используют десятки других классов rectangle.getX(), то вы пишете код, который не является устойчивым к «эффекту ряби» (насколько далеко изменение кода влияет на другой код). Просто спросите, что произойдет, если вы измените тип с intна double? Согласно этому обсуждению, многие rectangle.getX()звонки должны бытьrectanlge.calculateThisThingForMe(), Таким образом, очень косвенно, дублированный код может появиться из многих переменных экземпляра, так как многие классы используют много методов получения и установки, делающих очень похожие вещи, то есть копируемые вещи, которые лучше перемещать внутри класса.

Многие или несколько переменных экземпляра остаются постоянным компромиссом, меняя оба пути по мере роста программного обеспечения.

peter_the_oak
источник
Цитата R-to-P слишком общая, поэтому мне нравится этот ответ. Мой вывод: если мы представим достаточно свойств, клиент может, и будет, взять их и написать свою собственную версию данной функциональности - # 4 выше. Проблема может доходить до такой же глубины, как и состав объекта - см. № 2. Я слишком часто вижу это в нашем коде. (а) «почему они не использовали класс <что угодно> (чтобы загнать часть этого неорганизованного состояния)?» или (б) «Почему они не сделали новый класс? Я не могу отследить все это». И, конечно же, у нас есть несколько классов, дублирующих внутреннюю функциональность из-за отсутствия связного класса.
радар Боб
6

Проще говоря: плохое разделение проблем внутри кода, приводит к тому, что код не является модульным, приводит к плохому повторному использованию, приводит к дублированию кода.

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

Если вы попытаетесь повторить функциональность, то монолитный код, который не является модульным, не может быть повторно использован. Он делает слишком много и может делать только то, что делает. Чтобы сделать что-то подобное, но не то же самое, «проще» вырезать и вставлять, чем разбивать монолитный код. Опыт программистов знает, что дублированный код - это дорога в ад.

Поэтому, хотя многие переменные экземпляра сами по себе не являются основной причиной проблемы, это сильный «запах» того, что проблема возникает.

Язык «не может быть далеко позади» слабее, чем «обязательно должен следовать», поэтому автор не утверждает, что это должно произойти, но в конечном итоге произойдет; если вам нужно повторно использовать функциональность, но не можете, поскольку код не является модульным.

simbo1905
источник