Почему классы данных считаются запахом кода?


18

В этой статье утверждается, что класс данных - это «запах кода». Причина:

Это нормально, когда недавно созданный класс содержит только несколько открытых полей (и, возможно, даже несколько получателей / установщиков). Но истинная сила объектов в том, что они могут содержать типы поведения или операции над своими данными.

Почему для объекта неправильно содержать только данные? Если основная ответственность класса заключается в представлении данных, разве не будут добавлены методы, которые работают с данными, нарушающими принцип единой ответственности ?


1
Это будет сильно зависеть от языковых особенностей. Например, в Python нет различия между «полем» и его средствами доступа, если только вы не пытаетесь писать Java на Python .
ОАО

1
Я думаю, что наличие некоторых классов только для данных само по себе не является запахом кода, но если большинство классов таковы, то мы говорим об антипаттерне «анемичный домен» en.wikipedia.org/wiki/Anemic_domain_model
Tulains Córdova

1
Я не вижу, как этот вопрос является дубликатом. Другие вопросы касаются использования классов данных в ОО, в то время как этот вопрос касается недостатков классов данных - совершенно других предметов.
Милош Мрдович

Возможно, вы захотите прочитать этот ответ о стековом потоке, который гораздо более дифференцирован, чем ответ с верхним голосом, который постулирует неполноценность модели с богатым доменом и представляет его как доказанный факт. stackoverflow.com/questions/23314330/…
McLovin

Ответы:


31

Нет ничего плохого в том, чтобы иметь чистые объекты данных. Откровенно говоря, автор произведения не знает, о чем говорит.

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

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


1
Просто хотел добавить, что чистые объекты данных могут быть неоценимы для моделирования отношений, валидации, контроля доступа / изменений.
Адриан

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

7
Если функция принимает аргумент этого типа данных, она уже связана с данными.
RemcoGerlich

4
Пониженное голосование, потому что это неправильно, или, в лучшем случае, вопрос мнения. На языке ОО обычно имеет смысл иметь объект, содержащий как данные (которые все еще могут быть неизменяемыми!), Так и методы, которые воздействуют на него. Чистые функции и отдельные данные прекрасно подходят для других языковых парадигм, но если вы делаете OO, делайте OO полностью.
Марнен Лайбоу-Козер

3
Реальность показала нам много вещей. -1 для догматического всезнайки мнения «другие потерпели неудачу». Кроме того, автор не говорит, что чистые объекты данных являются «неправильными», просто они являются «запахом кода» и заслуживают сомнений. Я только сожалею о том, что у меня есть одно снижение, чтобы дать для моей страны. :-)
user949300

7

Нет ничего плохого в том, чтобы иметь чистые объекты данных. У автора есть мнение, не разделяемое разработчиками программного обеспечения, которых я знаю.

Специально для отображения базы данных у вас вообще есть классы сущностей, которые содержат только поля, хранящиеся в базе данных, а также методы получения и установки. Википедия Hibernate (рамки)

Идея дырки Java-бинов, используемых многими инструментами / средами, основана на классах данных, называемых бинами, которые содержат только поля и связанные методы получения и установки. Wikipdia JavaBeans

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


Автор не говорит, что чистые объекты данных являются «неправильными». Они говорят, что чистые объекты данных - это «запах кода», что означает, что вам следует дважды подумать об их использовании.
user949300

1
@ user949300, ты, кажется, запутался. Если автор называет их запахом кода, он указывает, что с ними что-то не так. Поскольку в наши дни они широко признаны как очень хорошая практика, они явно не являются запахом кода. Таким образом, MrSmith42 прав: с ними все в порядке.
Дэвид Арно

4

Хороший аргумент, почему Мартин Фаулер:

«Tell-Don't-Ask - это принцип, который помогает людям помнить, что объектная ориентация заключается в объединении данных с функциями, которые работают с этими данными. Он напоминает нам, что вместо того, чтобы запрашивать у объекта данные и действовать на основе этих данных, мы вместо этого следует сказать объекту, что делать. Это побуждает перемещать поведение в объект для передачи данных ».

https://martinfowler.com/bliki/TellDontAsk.html


1
Проблема здесь в том, что Фаулер искусственно ограничивает «говори не спрашивай», изменяя функции от запроса более широкой области к просто запросу области действия объекта. Они все еще спрашивают. «Скажи, не спрашивай», на самом деле, можно сделать еще один шаг, действительно передав эти функции через списки аргументов. И, таким образом, мы получаем объекты данных и отдельные (с точки зрения данных) функции, являющиеся истинной реализацией «говори не спрашивай». Таким образом, вместо того, чтобы быть хорошим аргументом для утверждения, что классы данных являются запахом кода, на самом деле это еще раз доказывает обратное.
Дэвид Арно

2
@DavidArno Вы забываете об инкапсуляции и сокрытии. Вы указываете объекту выполнить метод-член, и метод-член входит в черный ящик объекта и делает все возможное, чтобы получить ответ. Если вы запрашиваете объект извне, у вас нет доступа к его частному состоянию, и поэтому либо объект предоставляет больше состояния, чем разумно, либо запрашивающему приходится перепрыгивать через большее количество обручей, чем это необходимо. Я не понимаю, почему вы когда-либо «просили» объект в ОО-среде. (Конечно, другие парадигмы программирования могут требовать других подходов.)
Марнен Лайбоу-Козер

2
@DavidArno Конечно, вы можете передать bazв качестве параметра статический метод, но для этого вам сначала нужно запросить объект. Возможно, в парадигме программирования, где методы были первичными (как, скажем, функциональное программирование), это имеет смысл, но в ОО-среде это абсолютно не так, потому что объекты являются первичными и должны содержать как данные, так и функции, которые будут воздействовать на него. Насколько я могу судить, ваше утверждение о том, что удаление метода из объекта привело к увеличению инкапсуляции, также является в точности обратным , поскольку это означает, что теперь вы bazпоявлялись за пределами объекта.
Марнен Лайбоу-Козер

1
@ MarnenLaibow-Koser, я не утверждаю, что "делаю OO". Я пишу код и использую хорошие методы для этого. Происходят ли эти методы из функциональной парадигмы, или из ОО-парадигмы, или из парадигмы «кто-то-да-черт», мне не интересно. Выбор парадигмы и максимально полное ее соблюдение - чистая догма. Это плохо. Это нелепо. Это душит вас и приводит к ухудшению кода. Не делай этого.
Дэвид Арно

1
@DavidArno Напротив, если вы полностью посвятите себя парадигме (любой достойной парадигме, а не только ОО), вы получите мощные высокоуровневые абстракции и логически непротиворечивый, поддерживаемый код. Я не говорю, что это догматично, а скорее прагматично. Я видел и поддерживал слишком много кода, который, по-видимому, был создан с таким отношением, как у вас, когда автор на самом деле не придерживался логической последовательности используемой системы. Это трудно понять, трудно поддерживать и трудно изменить. Ни одна парадигма не является идеальной, но, как правило, смесь (если ее тщательно не рассмотреть) труднее понять.
Марнен Лайбоу-Козер

2

Вам нужно понять, что существует два вида объектов:

  • Объекты, которые имеют поведение . Они должны воздерживаться от предоставления публичного доступа большинству / любому из своих членов данных. Я ожидаю только очень мало методов доступа, определенных для них.

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

    Большинство классов, которые я пишу, относятся к этой категории.

  • Объекты, которые на самом деле просто данные . Они должны просто объявить всех своих членов публичными (или предоставить им полный набор средств доступа).

    Примером будет класс Point2D. Абсолютно нет инварианта, который должен быть гарантирован для членов этого класса, и пользователи должны иметь возможность просто получать доступ к данным через myPoint.xиmyPoint.y .

    Лично я не очень часто использую такие классы, но я полагаю, что нет более крупного кода, который я написал, где бы не использовался такой класс.

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


Если вы кодируете на C ++, вы можете сделать это различие явным, используя classдля первой категории объектов и structдля второй. Разумеется, они эквивалентны, за исключением того, classчто по умолчанию все члены являются закрытыми, а по умолчанию structобъявляет всех участников открытыми. Какую именно информацию вы хотите сообщить.


1
Объяснение понижающего голоса было бы круто ...
cmaster - восстановить

Спасибо за ответ. Я ненавижу, когда люди понижают голос без причины. Если у вас есть проблема с ответом, объясните почему .
Сипо
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.