web-dev-qa-db-fra.com

Les objets de OOP doivent-ils représenter une entité?

n objet doit-il représenter une entité?

Par entité je veux dire quelque chose comme un Product, Motor, un ParkingLot etc, un physique, ou même un non-physique clair objet conceptuel - quelque chose de bien défini, avec certaines données de base appartenant clairement à l'objet, et certaines fonctions/méthodes qui opèrent clairement sur les données de base.

Par exemple, je peux avoir un objet d'un Demon, une entité en soi, peut-être imaginaire et non pas physique mais une entité quand même

Un objet peut-il être juste un ensemble de méthodes , un ensemble commun de procédures qui se rattachent à un objectif commun?

Exemple: une classe peut-elle être appelée MotorOperations ou MotorActions, où il n'y a pas d'entité, mais les méthodes à l'intérieur de la classe font des choses comme

  • getMotorDataFromHTMLForm ()
  • getMotorManufacturers ()
  • selectMotorFromUserRequirements ($ requirements)
  • canMotorCanHandleOperatingConditions ($ conditions)
  • computePowerConsumptionForMotor ($ id)

Une classe est généralement définie comme une donnée centrale de l'objet + opérations sur les données. Ainsi, pour un Motor, il peut y avoir des variables de moteur liées aux spécifications du moteur, et il peut y avoir des opérations qui combinent ces données pour produire quelque chose.

Dans mon cas, c'est plus comme si j'avais une classe avec des opérations sur les données + les données qui sont passées à travers la classe, il n'y a pas de données centrées sur "Motor" Opérations ", à l'exception des données temporaires de la classe.

Question

Les classes peuvent-elles représenter des objets sans entité? Sinon, pourquoi sont-ils mauvais/incomplets/non centrés sur la POO? Existe-t-il des moyens de les modifier/les améliorer conceptuellement pour les aligner sur la POO?

83
Dennis

Non , un objet n'a pas à représenter une entité.

En fait, je dirais que lorsque vous cessez de considérer les objets comme des entités physiques, c'est quand vous obtenez enfin les avantages promis par OOP.

Ce n'est pas le meilleur exemple, mais le conception de la cafetière est probablement l'endroit où la lumière a commencé à s'allumer pour moi.

Les objets concernent des messages. Ils concernent les responsabilités. Ils ne concernent pas les voitures, les utilisateurs ou les commandes.

Je sais que nous enseignons OO de cette façon, mais il devient évident après quelques essais à quel point il est fondamentalement frustrant de comprendre où vont les choses lorsque vous essayez de faire MVC, MVVM ou MVW Quoi que ce soit. Soit vos modèles deviennent ridiculement gonflés ou vos contrôleurs le font. Pour la navigabilité, il est bon de savoir que tout ce qui touche les véhicules se trouve dans le fichier Vehicle.ext, mais lorsque votre application concerne les véhicules, vous vous retrouvez inévitablement avec 3000 lignes de spaghetti dans ce fichier.

Lorsque vous avez un nouveau message à envoyer, vous avez au moins un nouvel objet, et peut-être une paire d'entre eux. Donc, dans votre question sur un ensemble de méthodes, je dirais que vous parlez potentiellement d'un ensemble de messages. Et chacun pourrait être son propre objet, avec son propre travail à faire. Et ça va. Cela deviendra évident lorsque vous séparerez les choses, lesquelles doivent vraiment, vraiment être ensemble. Et vous les mettez ensemble. Mais vous ne déposez pas immédiatement chaque méthode dans un tiroir vaguement approprié pour plus de commodité si vous voulez profiter de OO.

Parlons de sacs de fonctions

Un objet peut être juste une collection de méthodes et toujours être OO, mais mon les "règles" sont assez strictes.

  1. La collection devrait avoir une seule responsabilité, et cette responsabilité ne peut pas être aussi générique que "Fait des choses pour les moteurs". Je pourrais faire une chose comme une façade de couche de service, mais je suis profondément conscient que je suis paresseux pour des raisons de navigabilité/découverte, pas parce que j'essaie d'écrire OO code .

  2. Toutes les méthodes doivent être à une couche d'abstraction cohérente. Si une méthode récupère des objets Motor et une autre renvoie Horsepower, c'est probablement trop éloigné.

  3. L'objet doit fonctionner sur le même "type" de données. Cet objet fait des choses sur les moteurs (marche/arrêt), celui-ci fait des choses avec des longueurs de manivelle, celui-ci gère le séquencement de l'allumage, celui-ci prend une forme html. Ces données pourraient en théorie être des champs sur l'objet et elles sembleraient cohérentes.

Je construis généralement des objets de ce type lorsque je fais des transformations, de la composition ou que je ne veux tout simplement pas m'inquiéter de la mutabilité.

Je trouve que me concentrer sur les responsabilités des objets me conduit vers la cohésion. Il doit y avoir une certaine cohésion pour être un objet, mais il n'y a pas besoin de champs ni de comportement pour qu'il soit un objet. Si je construisais un système qui avait besoin de ces 5 méthodes motrices, je commencerais avec 5 objets différents qui font ces choses. Comme je trouvais des points communs, je commençais soit à fusionner les choses, soit à utiliser des objets "auxiliaires" communs. Cela m'amène dans des préoccupations ouvertes/fermées - comment puis-je extraire ce peu de fonctionnalité afin de ne jamais avoir à modifier à nouveau ce fichier particulier mais de l'utiliser quand cela est nécessaire?

Les objets concernent les messages

Les champs importent à peine à un objet - obtenir et définir des registres ne change pas le monde en dehors du programme. Collaborer avec d'autres objets fait le travail. Cependant, la force de OO est que nous pouvons créer des abstractions pour ne pas avoir à penser à tous les détails individuels à la fois. Les abstractions qui fuient ou qui n'ont pas de sens sont problématiques, donc nous pensons profondément (trop, peut-être) à la création d'objets qui correspondent à nos modèles mentaux.

Question clé: Pourquoi ces deux objets doivent-ils se parler?

Considérez l'objet comme un organe d'une personne - il a un objectif par défaut et ne change de comportement que lorsqu'il reçoit un message spécifique qui lui tient à cœur.

Imaginez un scénario où vous êtes dans le passage pour piétons et où une voiture arrive rapidement. En tant qu'objet cérébral, je détecte un facteur de stress. Je dis à l'hypothalamus d'envoyer une hormone libérant de la corticotrophine. L'hypophyse reçoit ce message et libère l'hormone corticotrophique surrénale. Les glandes surrénales reçoivent ce message et créent de l'adrénaline. Lorsque l'objet musculaire reçoit ce message d'adrénaline, il se contracte. Lorsque le cœur reçoit le même message, il bat plus vite. Il y a toute une chaîne de joueurs impliqués dans le démarrage du comportement complexe du sprint à travers la rue et ce sont les messages qui comptent. L'objet cérébral sait comment faire en sorte que l'hypothalamus envoie l'alerte, mais il ne connaît pas la chaîne d'objets qui finira par provoquer le comportement. De même, le cœur n'a aucune idée d'où vient l'adrénaline, il sait juste faire quelque chose de différent quand cela se manifeste.

Ainsi, dans cet exemple ( simplifié), l'objet glande surrénale n'a besoin que de savoir comment prendre l'ACTH et fabriquer de l'adrénaline. Il n'a pas besoin de champs pour cela, mais il me semble toujours être un objet.

Maintenant, si notre application est conçue uniquement pour sprinter à travers la rue, je n'ai peut-être pas besoin de l'hypophyse et des objets de la glande surrénale. Ou j'ai seulement besoin d'un objet de glande pituitaire qui ne fait qu'une petite partie de ce que nous pourrions conceptuellement considérer comme le "modèle de la glande pituitaire". Ces concepts existent tous en tant qu'entités conceptuelles, mais c'est un logiciel et nous pouvons faire le AdrenalineSender ou MuscleContractor ou quoi que ce soit et ne pas trop se soucier de "l'incomplétude" de notre modèle.

109
Steve Jackson

Les classes peuvent-elles représenter des objets sans entité? Sinon, pourquoi sont-ils mauvais/incomplets/non centrés sur la POO? Existe-t-il des moyens de les modifier/les améliorer?

En bref, vous pouvez tout faire, mais ce scénario spécifique serait contraire aux principes OOP :)

Ce que vous décrivez est parfois appelé une classe "utilitaire" - généralement un signe d'odeur de code. Vous voulez éviter de créer des classes pour garder certaines méthodes ensemble.

Tous les objets de votre application ne doivent pas être liés à une entité réelle comme un moteur ou une voiture; ce sont des objets métier. Dans votre application, vous utiliserez probablement un grand nombre de vos objets métier, mais vous aurez également besoin d'une plus grande ségrégation pour d'autres opérations qui ne font pas partie d'entités commerciales, comme celles que vous avez répertoriées.

Vous devriez jeter un œil aux modèles architecturaux courants - l'un d'eux est MVC (Model-View-Controller) .

Si je devais distribuer les méthodes que vous avez répertoriées à l'aide de MVC, voici ce que je ferais:

Afficher la classe:

  • GetMotorDataFromHTMLForm ()

Classe de modèle (moteur essentiellement):

  • GetMotorManufacturer ()
  • CanMotorHandleOperationConditions ()
  • CalculatePowerConsumption ()

Classe de contrôleur (MotorsController):

  • GetAllMotors ()
  • GetMotorById ()
  • GetMotorByUserRequirements ()

Il semble que vous utilisiez PHP; un bon framework MVC pour y jeter un œil est Laravel . Dans leurs exemples, ils illustrent bien à quoi appartiennent les méthodes.

Une autre source d'informations plus générique sur la façon de décider de l'appartenance des méthodes est [~ # ~] saisir [~ # ~] et [~ # ~] solid [~ # ~ ] principes.

21
Alexus

Les classes peuvent-elles représenter des objets sans entité?

Pouvez? Oui. Devrait? Probablement pas - ou du moins, pas comment vous formulez les choses.

Les objets sont en fait meilleurs lorsque pas représentant directement un objet physique, car la réalité est rarement associée au code. Mais ils doivent représenter un concept cohérent ou un objet code. Ils doivent représenter une seule responsabilité cohérente.

Le regroupement d'un ensemble de fonctions liées de manière tangentielle est un espace de noms ou un module - pas un objet dans le langage OOP. Ceux-ci peuvent être utiles, mais ils ne sont pas les mêmes et nécessitent un tri différent d'utilisation/de réflexion pour travailler efficacement.

15
Telastyn

Une classe devrait modéliser quelque chose - sinon c'est inutile. Cependant, ce qui est modélisé peut ne pas être une "chose" physique; au lieu de cela, il peut s'agir d'une représentation de quelque chose qui n'est pas "réel", mais qui est nécessaire pour contrôler le système modélisé. Par exemple, dans un système de contrôle des feux de circulation, vous pourriez très bien avoir une sorte de classe ControlSignal, représentant un signal envoyé d'une partie du système à une autre pour indiquer qu'une action doit être effectuée. Dans "le monde réel", ces signaux peuvent consister en des impulsions électriques transmises à travers des fils d'un boîtier à un autre. Le processus de modélisation de quelque chose qui n'est pas "réel" en tant qu'objet concret est appelé "réification".

Bonne chance.

Non. (Titre modifié pour poser la question opposée!)

par exemple:

Public class MyRepository
{
    public MyObject GetObject(string id)
    {
        //get data from the DB and build an object
    }
}

ou

Public class MyService
{
    public MyObject3 ProcessData(MyObject1 obj1, MyObject2 obj2)
    {
         //perform a process which is not a sole responsiblity of obj1 or obj2
    }
}

Cependant, en général, l'idéal derrière OOP est de s'éloigner de

public struct Car
{
    public Wheel[] Wheels;
}

public int CountWheelsOnCar(MyCarStruct car)
{
   return car.Wheels.Length;
}

à

public class Car
{
    private Wheel[] wheels;
    Public int CountWheels()
    {
        return this.wheels.Length;
    }
}
7
Ewan

Un objet doit-il représenter une entité?

Question: Quelle entité représente un Logger?

Pas métaphoriquement - littéralement.

Lorsque vous expliquez OOP aux élèves, il est utile d'expliquer les objets ayant des analogies avec le monde physique.

Alan Kay - l'un des pères de [~ # ~] oop [~ # ~] - a écrit ce qui suit:

[...]

Sa conception originale comportait les parties suivantes.

  • Je pensais que les objets étaient comme des cellules biologiques et/ou des ordinateurs individuels sur un réseau, seulement capables de communiquer avec des messages
  • Je voulais me débarrasser des données.

[...]

Pour moi, la POO signifie uniquement la messagerie, la conservation et la protection locales et

la dissimulation du processus étatique et l'extrême liaison tardive de toutes choses.

architecture HW presque incroyable. J'ai réalisé que le

la métaphore de la cellule/de tout l'ordinateur se débarrasserait des données

source

De cela, les objets sont mieux compris comme

  • objets autarciques encapsulant/cachant des données

  • communiquer avec d'autres objets via des messages

Les classes peuvent-elles représenter des objets sans entité?

Certainement: pensez à Math


Concernant votre exemple:

Exemple: une classe peut-elle être appelée MotorOperations ou MotorActions, où il n'y a pas d'entité, mais les méthodes à l'intérieur de la classe font des choses comme

  • getMotorDataFromHTMLForm ()

  • getMotorManufacturers ()

  • selectMotorFromUserRequirements ($ requirements)

  • canMotorCanHandleOperatingConditions ($ conditions)

  • computePowerConsumptionForMotor ($ id)

Pour décider où placer ces méthodes, vous devez jeter un œil à responsibilities: qui est responsable de quoi.

getMotorDataFromHTMLForm ()

Le contexte d'une telle méthode serait construire un moteur-objet. Ce n'est pas la responsabilité du moteur de se créer à partir des données récupérées via un formulaire. Il y a au moins deux objets impliqués; l'un est le moteur et l'autre est le créateur du moteur.

getMotorManufacturers ()

Le contexte typique dans lequel on écrirait une telle méthode est un service.

selectMotorFromUserRequirements ($ requirements)

Cela serait également utilisé dans un contexte service-

canMotorCanHandleOperatingConditions ($ conditions)

Ceci est une question à un objet motor-

computePowerConsumptionForMotor ($ id)

C'est aussi une question qu'il vaut mieux poser au moteur lui-même.


tl; dr

La métaphore de objects as objets physiques est plus irritante qu'utile.

5
Thomas Junk

Je pense que visualiser quelque chose dans le monde réel est utile lors du codage des classes mais pas nécessaire.

En fait, selon la façon dont vous voulez être littéral, de nombreux objets avec lesquels nous travaillons n'ont pas du tout de représentations physiques. Par exemple, considérez l'architecture MVC. Dans le monde réel, il n'y a pas de modèle ou de contrôleur, même s'ils sont généralement représentés par des classes. Les trois ensemble représentent souvent quelque chose, mais pas toujours - mais comme je l'ai dit, vous pourriez probablement forcer un ajustement dans quelque chose si vous le voulez vraiment (et être capable d'imaginer QUELQUE CHOSE aide! Je visualise la plupart des objets d'une manière ou d'une autre - juste pas n'importe quoi vous verriez jamais dans le monde réel).

Surtout ces "règles", vous en apprendrez sur OO ne sont que des lignes directrices destinées à vous orienter vers la réflexion en OO pas nécessairement des choses qui vous inquiètent beaucoup une fois que vous êtes en l'utilisant pour coder quotidiennement.

Au fait OO lui-même n'est pas une panacée et cela ne vous aide pas du tout lors de votre première passe à coder une solution, mais je pense que si c'est bien fait, c'est vraiment fantastique moyen d'organiser le code afin qu'il puisse être plus facilement compris plus tard. L'écriture de code maintenable est probablement l'une des tâches les plus difficiles dans le développement de logiciels et dans de nombreux cas (tout ce qui nécessite un débogage/maintenance continu), c'est de loin le plus important.

5
Bill K

Dans les mots du profane

  • Ce que vous décrivez s'appelle une classe utilitaire.
  • Il n'a pas d'état, ce qui signifie que vous n'aurez jamais vraiment besoin d'en avoir plusieurs instances
  • Toutes les méthodes sont statiques, ce qui signifie que vous devez tout passer en tant que paramètres

De telles classes existent, par exemple le SDK Java SDK a la classe Collections qui se compose exclusivement de méthodes statiques qui opèrent sur ou retournent des collections.

La réponse serait donc non, toutes les classes n'ont pas besoin d'être modélisées à partir d'une entité de domaine.

D'un autre côté, de telles classes ne sont que quelques-unes ou ne devraient l'être que dans un programme créé dans un langage OOP, car la puissance réelle de OOP réside dans le polymorphisme et l'encapsulation.

Ce serait comme utiliser un avion pour aller d'un endroit à un autre non pas en volant mais en le conduisant sur des autoroutes. Les avions ont des roues comme les voitures, mais ils sont destinés à voler.

3
Tulains Córdova

Oui, vous pouvez le faire. Mais vous créez essentiellement une classe pour fournir les mêmes fonctionnalités qu'une bibliothèque procédurale. La seule raison de le faire est que votre langage manque de modules procéduraux (par exemple, Java ou Ruby).

Dans un langage avec des modules procéduraux (je pense PHP a des modules procéduraux), vous pourriez envisager d'utiliser simplement un module procédural.

Vous pouvez également envisager de reconcevoir votre classe afin qu'une instance de la classe représente un objet cohérent.

Mais utilisez uniquement la notation OO lorsqu'elle vous donne plus de puissance, pas seulement pour être OO!

3
Jonathan Cast

Non, une classe représente simplement quelque chose qui peut être instancié, a des membres et peut être hérité.

En fait, votre langage peut avoir des classes statiques, qui ne sont même pas instanciées plusieurs fois.

. NET's Math est un excellent exemple d'une classe "professionnelle" qui ne représente aucune entité (à moins que vous ne vouliez vous familiariser avec les mathématiques ...), et arrive aussi à illustrent un cas d'utilisation légitime d'une telle classe. Il n'a que des méthodes et 2 champs (tous deux représentant des constantes individuelles).

La hiérarchie des classes d'une bibliothèque similaire, Math.Net , regroupe les méthodes mathématiques/numériques en classes par type. Ici, les classes ne représentent pas une entité, mais une catégorie logique.

Moi-même, je finis souvent par créer des classes (statiques) qui ne sont rien d'autre qu'un sac de fonctions (statiques) liées, ou un tas de constantes regroupées de manière pratique en un seul endroit central. Je ne dirais pas que c'est une bonne conception, mais parfois c'est la solution la plus simple.

2
Superbest

Les réponses à vos questions dépendent finalement de la précision avec laquelle on définit des termes comme "classe" et "entité". Vous avez bien réussi à définir ce dernier, en permettant à la fois des entités physiques et conceptuelles. Mais le terme "classe" pour les puristes sera toujours "une usine pour instancier des objets avec une représentation interne particulière" et pour les pragmatistes, le terme englobera ces Java ou C++ choses méprisées par les puristes. Idem pour le terme "OOP", que les pragmatistes pourraient dire Java et C++, mais que les puristes prendraient pour signifier ce qu'Alan Kay voulait dire quand il remarquait ["J'ai inventé le terme orienté objet, et je peux vous dire que je ne pensais pas au C++ "] ( Alors * qu'Alan Kay voulait-il vraiment dire par le terme" orienté objet "? ).

Si vous adoptez la vue pragmatique, vous pouvez accepter vos classes d'utilitaires sans instance. Mais la vision puriste est plus intéressante. La POO, selon Kay, était toujours plus à propos des messages que des classes. Donc à vos questions:

Les classes peuvent-elles représenter des objets sans entité?

No. Classes classify objets. Les classes sont par définition les entités auxquelles vous envoyez un message tel que new pour produire un objet. Un objet est une entité créée à partir d'une classe. Il existe des classes pour fabriquer, voire classer, des objets. C'est ce que font les classes. Les classes font des objets. Nous utilisons des classes pour classer les objets. Donc, si C est juste un ensemble de méthodes qui ne permet pas l'instanciation ou le sous-classement, il ne peut pas y avoir d'objets classés par C, donc C n'est pas une classe.

Sinon, pourquoi sont-ils mauvais/incomplets/non centrés sur la POO?

Ils ne sont pas mauvais. Ne les appelez pas classes. Un ensemble de méthodes is OOPable: quelque chose auquel vous pourriez envoyer un message afin d'invoquer une méthode, mais ce n'est pas une classe à moins qu'elle ne puisse instancier un objet. Connaissez-vous Ruby? Dans Ruby a module est un ensemble de méthodes. A class est un module qui peut instancier des objets. Il n'y a rien de mal à propos d'un module. Mais ce qui rend une classe différente d'un module (en termes purs OOP), c'est qu'une classe peut avoir des instances. Un module n'est que quelques méthodes. La confusion est que C++ et Java et d'autres langages utilisent le terme "classe" pour la classe et le module .

Maintenant, pour regarder l'un de vos exemples spécifiques, vous demandez une classe MotorOperations à laquelle vous pourriez envoyer le message computePowerConsumptionForMotor avec l'argument id. Est-ce mauvais? Au moins, il ne viole pas le principe Tell Don't Ask . Avons-nous avons pour créer une classe de moteur et lui envoyer le message powerConsumption? Peut-être pas à 100% du temps, mais peut-être qu'essayer de faire de telles choses mènera à quelques bonnes idées sur votre code. Ou, cela peut conduire à une explosion de petites classes, ce qui serait mauvais.

Existe-t-il des moyens de les modifier/les améliorer conceptuellement pour les aligner sur la POO?

Si "faire de la POO" est important pour vous, alors vous voudrez chercher des façons d’architecturer un système en composants qui communiquent en s’envoyant des messages. C'est exactement ce que OOP est , ou du moins ce que le concepteur du terme avait en tête. Les classes utilitaires ne sont pas OOP dans cette vue. Mais pour certaines personnes, ils peuvent l'être.

Essayer de créer un grand système entier à partir de millions d'objets vivants, respirants, tous instanciés en classe, peut fonctionner pour certains projets. Mais si vous vous retrouvez en train de créer des classes artificielles au mauvais son, alors des modules devraient être introduits. Essayez de mettre l'accent sur les classes et utilisez des modules lorsque des classes instanciables seraient ridicules.

TL; DR - les bundles de méthodes ne sont pas toujours mauvais. Essayez d'abord d'utiliser des classes instanciables. Revenez aux "modules" uniquement en cas de besoin.

1
Ray Toal

Un objet est un ensemble de méthodes et de données à haute cohésion. Ils appartiennent à une classe car ils sont étroitement liés et l'état est conservé.

Cela est vrai que vous utilisiez une conception avant-gardiste et tentiez de tout modéliser, ou une conception émergente où vous répétez et faites évoluer l'objet en ce qui correspond aux besoins du système à l'époque.

Si vous n'avez aucune raison de conserver l'état, vous n'avez probablement aucune raison d'instancier un objet, ce qui signifie qu'il n'y a probablement aucune raison d'avoir une classe. À moins que la langue que vous utilisez n'ait la capacité de définir un espace de noms autre que l'utilisation de la classe. Dans quelle classe utiliser devrait être bien parce que ce serait idiomatique.

Je ne peux penser à aucun aspect négatif de l'utilisation des cours de cette manière autre que le typique. Vous invitez des coûts et une complexité inutiles en ayant à instancier un "espace de noms". Quiconque prend en charge ce code se demandera où les données coûtent une charge cognitive supplémentaire (très probablement un coût unique par personne). C'est une utilisation inhabituelle sans aucune valeur supplémentaire.

0
dietbuddha

Prenant les exemples donnés:

getMotorDataFromHTMLForm()
selectMotorFromUserRequirements($requirements)

Celles-ci ressemblent à des méthodes "d'usine", qui renverraient un objet Motor. La seconde implique que soit vous créez un nouvel objet pour répondre aux exigences, soit vous disposez d'une base de données ou d'une collection de moteurs en mémoire que vous examinez. Dans ce cas, ce devrait être une méthode à ce sujet. Ou ce pourrait être une méthode sur l'objet d'exigences.

getMotorManufacturers()

D'où les obtenez-vous? Voilà ce que cela devrait être une méthode.

canMotorCanHandleOperatingConditions($conditions)
computePowerConsumptionForMotor($id)

Celles-ci semblent être des méthodes sur Motor.

0
pjc50