web-dev-qa-db-fra.com

Pourquoi les classes de données sont-elles considérées comme une odeur de code?

This article prétend qu'une classe de données est une "odeur de code". La raison:

C'est une chose normale quand une classe nouvellement créée ne contient que quelques champs publics (et peut-être même une poignée de getters/setters). Mais la vraie puissance des objets est qu'ils peuvent contenir des types de comportement ou des opérations sur leurs données.

Pourquoi un objet ne contient-il que des données? Si la responsabilité principale de la classe est de représenter les données, n'ajouterait-il pas des méthodes qui opèrent sur les données pour briser le principe de responsabilité unique ?

18
Sipo

Il n'y a absolument rien de mal à avoir des objets de données purs. Franchement, l'auteur de la pièce ne sait pas de quoi il parle.

Une telle pensée découle d'une vieille idée, échouée, selon laquelle "le vrai OO" est la meilleure façon de programmer et que le "vrai OO" est tout au sujet des "modèles de données riches" où l'on mélange les données et la fonctionnalité.

La réalité nous a montré que le contraire est vrai, en particulier dans ce monde de solutions multithread. Les fonctions pures, combinées à des objets de données immuables, sont un moyen manifestement meilleur de coder.

34
David Arno

Il n'y a absolument rien de mal à avoir des objets de données purs. L'auteur a une opinion non partagée par les développeurs de logiciels que je connais.

Surtout pour le mappage de bases de données, vous avez en général des classes d'entités qui ne contiennent que les champs stockés dans la base de données et les getters et setters. Wikipedia Hibernate (framework)

L'idée de trou de Java beans utilisés par de nombreux outils/frameworks est basée sur des classes de données appelées beans qui ne contiennent que des champs et les getters et setters associés. Wikipdia JavaBeans

Fazit:
Si quelqu'un prétend que quelque chose est "mauvais" ou "une odeur de code", vous devriez toujours chercher les raisons données. Si les raisons ne vous convaincent pas, demandez à quelqu'un d'autre de meilleures raisons ou une opinion différente. (Comme vous l'avez fait dans ce forum)

7
MrSmith42

Un bon argument pourquoi par Martin Fowler:

"Tell-Don't-Ask est un principe qui aide les gens à se rappeler que l'orientation objet consiste à regrouper des données avec les fonctions qui opèrent sur ces données. Cela nous rappelle qu'au lieu de demander des données à un objet et d'agir sur ces données, nous devrait plutôt indiquer à un objet ce qu'il doit faire. Cela encourage à déplacer le comportement dans un objet pour aller avec les données. "

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

4
Curtis Yallop

Ce que vous devez comprendre, c'est qu'il existe deux types d'objets:

  • Objets qui ont comportement. Ceux-ci devraient s'abstenir de donner au public l'accès à la plupart des membres de leurs données. Je n'attends que très peu de méthodes d'accesseur définies pour celles-ci.

    Un exemple serait un regex compilé: l'objet est créé pour fournir un certain comportement (pour faire correspondre une chaîne à un regex spécifique et pour signaler les correspondances (partielles)), mais comment le regex compilé fait son travail n'est pas l'affaire de l'utilisateur.

    La plupart des classes que j'écris appartiennent à cette catégorie.

  • Objets qui sont vraiment juste données. Ceux-ci devraient simplement déclarer tous leurs membres publics (ou fournir l'ensemble complet d'accesseurs pour eux).

    Un exemple serait une classe Point2D. Il n'y a absolument aucun invariant qui doit être assuré pour les membres de cette classe, et les utilisateurs devraient pouvoir simplement accéder aux données via myPoint.x et myPoint.y.

    Personnellement, je n'utilise pas beaucoup ces classes, mais je suppose qu'il n'y a pas de plus gros morceau de code que j'ai écrit qui n'utilise pas une telle classe quelque part.

Pour devenir compétent en orientation d'objet, il faut comprendre que cette distinction existe et apprendre à classer la fonction d'une classe dans l'une de ces deux catégories.


Si vous codez en C++, vous pouvez rendre cette distinction explicite en utilisant class pour la première catégorie d'objets et struct pour la seconde. Bien sûr, les deux sont équivalents, sauf que class signifie que tous les membres sont privés par défaut, tandis que struct déclare tous les membres publics par défaut. C'est exactement le genre d'informations que vous souhaitez communiquer.