web-dev-qa-db-fra.com

Quelle est la différence entre les objets et les structures de données?

J'ai lu le livre Clean Code: Manuel de l'artisanat agile en logiciels et au chapitre six, pages 95-98, il explique les différences entre les objets et les structures de données:

  • Les objets cachent leurs données derrière des abstractions et exposent des fonctions qui agissent sur ces données. Les structures de données exposent leurs données et n'ont aucune fonction significative.

  • Le comportement des objets et le masquage des données Cela facilite l'ajout de nouveaux types d'objets sans modifier les comportements existants. Cela rend également difficile l'ajout de nouveaux comportements aux objets existants.

  • Les structures de données exposent les données et n'ont aucun comportement significatif. Cela facilite l'ajout de nouveaux comportements aux structures de données existantes, mais rend difficile l'ajout de nouvelles structures de données aux fonctions existantes.

Je suis un peu confus si certaines classes sont des objets ou des structures de données. Disons par exemple HashMaps dans Java.util, sont-ils des objets? (En raison de ses méthodes telles que put (), get (), nous ne connaissons pas leur fonctionnement interne) ou s'agit-il de structures de données? (J'y ai toujours pensé comme des structures de données car c'est une carte). 

Les chaînes aussi, s'agit-il de structures de données ou d'objets?

Jusqu'à présent, la majorité du code que j'ai écrit était ce qu'on appelle des "classes hybrides" qui essaient aussi de jouer le rôle d'objet et de structure de données. Des conseils sur la façon de les éviter aussi?

27

La distinction entre les structures de données et les classes/objets est plus difficile à expliquer en Java qu'en C++. En C, il n'y a pas de classes, mais uniquement des structures de données, qui ne sont que des "conteneurs" de champs typés et nommés. C++ a hérité de ces "structures", vous pouvez donc avoir à la fois des structures de données "classiques" et des "objets réels".

En Java, vous pouvez "émuler" des structures de données de style C en utilisant des classes sans méthodes et uniquement des champs publics:

public class VehicleStruct
{
    public Engine engine;
    public Wheel[] wheels;
}

Un utilisateur de VehicleStruct connaît les pièces d'un véhicule et peut interagir directement avec ces pièces. Le comportement, c'est-à-dire les fonctions, doit être défini en dehors de la classe. C'est pourquoi il est facile de changer de comportement: L'ajout de nouvelles fonctions ne nécessite pas de code existant pour changer. En revanche, la modification des données nécessite des modifications dans pratiquement toutes les fonctions interagissant avec VehicleStruct. Cela viole l'encapsulation!

L'idée derrière OOP est de masquer les données et d'exposer le comportement. Il se concentre sur ce que vous pouvez faire avec un véhicule sans avoir à savoir s'il est équipé d'un moteur ou combien de roues sont installées:

public class Vehicle
{
    private Details hidden;

    public void startEngine() { ... }
    public void shiftInto(int gear) { ... }
    public void accelerate(double amount) { ... }
    public void brake(double amount) { ... }
}

Remarquez comment la Vehicle pourrait être une motocyclette, une voiture, un camion ou un réservoir - vous n'avez pas besoin de connaître les détails. Changer les données est facile - personne en dehors de la classe n'est au courant des données, donc aucun utilisateur de la classe n'a besoin d'être changé. Changer de comportement est difficile: toutes les sous-classes doivent être ajustées lorsqu'une nouvelle fonction (abstraite) est ajoutée à la classe.

Maintenant, en suivant les "règles d’encapsulation", vous pourriez comprendre que cacher les données consiste simplement à rendre les champs privés et à ajouter des méthodes d’accesseur à VehicleStruct:

public class VehicleStruct
{
    private Engine engine;
    private Wheel[] wheels;

    public Engine getEngine() { return engine; }
    public Wheel[] getWheels() { return wheels; }
}

Dans son livre, Oncle Bob affirme qu'en faisant cela, vous avez toujours une structure de données et non un objet. Vous modélisez toujours le véhicule comme la somme de ses pièces et exposez ces pièces à l'aide de méthodes. C'est essentiellement la même chose que la version avec des champs publics et un C vieux ancien struct - d'où une structure de données. Cacher des données et exposer des méthodes ne suffit pas pour créer un objet, vous devez déterminer si les méthodes exposent réellement comportement ou uniquement les données!

Lorsque vous mélangez les deux approches, par exemple Si vous exposez getEngine() avec startEngine(), vous vous retrouvez avec un "hybride". Je n'ai pas le livre de Martin sous la main, mais je me souviens qu'il ne recommandait pas du tout les hybrides, car vous vous retrouvez avec le pire des deux mondes: des objets où les données et le comportement sont difficiles à changer.

Vos questions concernant HashMaps et Strings sont un peu délicates, car elles sont plutôt simples et ne s'intègrent pas très bien dans le type de classe que vous allez écrire pour vos applications. Néanmoins, en utilisant les définitions données ci-dessus, vous devriez pouvoir y répondre.

Un HashMap est un objet. Il vous expose son comportement et cache tous les détails de hachage. Vous lui indiquez les données put et get, sans vous préoccuper de la fonction de hachage utilisée, du nombre de "compartiments" qu'il contient et du mode de gestion des collisions. En fait, vous utilisez HashMap uniquement via son interface Map, ce qui est une bonne indication de l’abstraction et des objets "réels". 

Ne vous trompez pas sur le fait que vous pouvez utiliser instances d'une carte en remplacement d'une structure de données!

// A data structure
public class Point {
    public int x;
    public int y;
}

// A Map _instance_ used instead of a data structure!
Map<String, Integer> data = new HashMap<>();
data.put("x", 1);
data.put("y", 2);

Un String, en revanche, est en gros un tableau de caractères et n'essaie pas de le cacher beaucoup. J'imagine que l'on pourrait appeler cela une structure de données, mais pour être honnête, je ne suis pas sûr qu'il y ait beaucoup à gagner d'une manière ou d'une autre.

18
Ferdinand Beyer

Un objet est une instance d'une classe. Une classe peut modéliser diverses choses du monde réel. C'est une abstraction de quelque chose (voiture, prise de courant, carte, connexion, étudiant, enseignant, etc.).

Une structure de données est une structure qui organise certaines données d’une certaine manière . Vous pouvez implémenter des structures de manière différente en utilisant des classes (c’est ce que vous faites dans des langages qui ne prennent pas en charge OOP; implémente toujours une structure de données en C, disons).

HashMap en Java est une classe qui modélise une structure de données de carte à l'aide d'une implémentation basée sur le hachage. C'est pourquoi elle s'appelle HashMap.

Socket en Java est une classe qui ne modélise pas une structure de données mais autre chose (un socket). 

4
peter.petrov

C'est ce que je crois, Robert. C. Martin essayait de transmettre:

  1. Les structures de données sont des classes qui agissent simplement comme des conteneurs de données structurées. Par exemple:

    public class Point {
        public double x;
        public double y;
    }
    
  2. Les objets, par contre, sont utilisés pour créer des abstractions. Une abstraction est comprise comme:

    une simplification de quelque chose de beaucoup plus compliqué qui se passe sous les couvertures The Law of Leaky Abstractions, Joel on Software

    Ainsi, les objets cachent tous leurs fondements et vous permettent uniquement de manipuler la essence de leurs données de manière simplifiée. Par exemple:

    public interface Point {
        double getX();
        double getY();
        void setCartesian(double x, double y);
        double getR();
        double getTheta();
        void setPolar(double r, double theta);
    }
    

    Où nous ne savons pas comment le point est implémenté, mais nous savons comment le consommer.

3
Enrique

Selon moi, Robert Martin essaie de faire comprendre aux objets que les objets ne doivent pas exposer leurs données via des accesseurs ni des setters, à moins que leur seul objectif soit de faire office de simples conteneurs de données. Les bons exemples de tels conteneurs peuvent être les beans Java, les objets d'entité (issus du mappage d'objets d'entités de base de données), etc.

Les classes de Java Collection Framework, cependant, ne sont pas un bon exemple de ce à quoi il fait référence, car elles n'exposent pas vraiment leurs données internes (qui sont dans de nombreux cas des tableaux de base). Il fournit une abstraction qui vous permet de récupérer les objets qu’ils contiennent. Ainsi (dans mon POV), ils entrent dans la catégorie "Objets".

Les raisons sont indiquées dans les citations que vous avez extraites du livre, mais il existe d'autres bonnes raisons de ne pas exposer les éléments internes. Les cours qui fournissent des getters et des setters invitent par exemple à enfreindre la loi de Demeter. En plus de cela, connaître la structure de l'état d'une classe (savoir quels sont ses getters/setters) réduit la capacité d'abstraction de l'implémentation de cette classe. Il y a beaucoup plus de raisons de ce genre.

3
eitanfar

Une structure data est littéralement une représentation structurée de certaines données. Il ne possède aucune "connaissance" intégrée autre que la structure et la dénomination des données. Un objet est beaucoup plus général et pourrait en réalité être n'importe quelle entité de votre système qui présente une interface d'interaction et peut être utilisé dans différents contextes. En particulier, un objet traditionnel class, par exemple, peut contenir des données et des méthodes appropriées pour accéder aux données, et ces données peuvent être spécifiques à une instance d'objet (par instance) ou au niveau de la classe.

Je ne suis pas sûr du terme "classe hybride" basé sur la description d'agir comme un objet ou une structure de données car une classe inclut souvent des données. Donc, cette terminologie semble redondante.

1
lurker

Une structure de données n'est qu'une abstraction, une manière particulière de représenter des données. Ce ne sont que des constructions faites par l’homme, qui aident à réduire la complexité au niveau supérieur, c’est-à-dire à ne pas travailler au niveau inférieur. Un objet peut sembler vouloir dire la même chose, mais la différence majeure entre les objets et les structures de données est qu'un objet peut tout abstrait. Il offre également un comportement. Une structure de données n'a aucun comportement, car il ne s'agit que d'une mémoire de stockage de données. 

Les classes de bibliothèques telles que Map, List, etc. sont des classes qui représentent structures de données. Ils implémentent et configurent une structure de données afin que vous puissiez facilement les utiliser dans vos programmes en créant des instances (objets). 

1
Sumanth

Les structures de données (DS) sont une manière abstraite de dire qu'une structure contient des données '. HashMap avec certaines paires de valeurs de clé est une structure de données en Java. Les tableaux associés sont similaires dans PHP, etc. Le nombre d'objets est légèrement inférieur au niveau DS. Votre hashmap est une structure de données. Maintenant, pour utiliser une table de hachage, vous créez un "objet" et ajoutez des données à cet objet en utilisant la méthode put. Je peux avoir ma propre classe Employee qui a des données et qui est donc un DS pour moi. Mais pour utiliser ce DS dans certaines opérations telles que: voir si l'employé est un collègue ou un collègue, j'ai besoin d'une instance d'employé et teste sa propriété de genre.

Ne confondez pas les objets avec les structures de données.

0
Nazgul