it-swarm.dev

Avantages de la programmation orientée objet

Remarque : cette question est un extrait édité d'un publication de blog que j'ai écrit il y a quelques mois. Après avoir placé un lien vers le blog dans un commentaire sur Programmers.SE quelqu'un a demandé que je poste une question ici afin qu'ils puissent y répondre. Cette publication est ma plus populaire, car les gens semblent taper "Je ne reçois pas de programmation orientée objet" dans Google beaucoup. N'hésitez pas à répondre ici, ou dans un commentaire sur Wordpress.

Qu'est-ce que la programmation orientée objet? Personne ne m'a donné de réponse satisfaisante. J'ai l'impression que vous n'obtiendrez pas une bonne définition de quelqu'un qui va dire "objet" et "orienté objet" avec le nez en l'air. Vous n'obtiendrez pas non plus une bonne définition de quelqu'un qui n'a fait que de la programmation orientée objet. Personne qui comprend à la fois la programmation procédurale et orientée objet ne m'a jamais donné une idée cohérente de ce que fait réellement un programme orienté objet.

Quelqu'un peut-il me donner ses idées sur les avantages de la programmation orientée objet?

35
Joel J. Adamson

Considérez le logiciel comme une machine ou une chaîne d'assemblage qui existe à l'intérieur de l'ordinateur. Certaines matières premières et certains composants sont introduits dans la machine, et il suit un ensemble de procédures pour les transformer en un produit final. Les procédures sont configurées pour effectuer une opération spécifique sur une matière première ou un composant selon un ensemble spécifique de paramètres (par exemple, temps, température, distance, etc.) dans un ordre particulier. Si les détails de l'opération à effectuer étaient incorrects, ou si les capteurs de la machine ne sont pas correctement étalonnés, ou si une matière première ou un composant n'était pas conforme aux normes de qualité attendues, cela pourrait changer le résultat de l'opération et le produit ne tournerait pas comme prévu.

Une telle machine est très rigide dans son fonctionnement et possède des entrées acceptables. Les machines ne remettent pas en cause l'intelligence des concepteurs ni son environnement d'exploitation actuel. Il continuera de suivre les procédures tant qu'il lui sera adressé. Même si un changement de matières premières ou de composants pouvait avoir un effet dramatique sur ce qui s'est passé lors d'opérations ultérieures, la machine exécuterait toujours ses procédures. Le processus devrait être revu pour voir quelles modifications aux procédures étaient nécessaires pour compenser et produire le résultat souhaité. Une modification de la conception ou de la configuration du produit peut également nécessiter une modification importante des opérations effectuées ou de leur commande. Bien que les responsables de la production aient rapidement compris l'importance d'isoler les opérations autant que possible pour réduire les effets indésirables entre elles, beaucoup d'hypothèses sont formulées quant à l'état des composants pendant leur traitement; hypothèses qui pourraient ne pas être détectées tant que le produit final n'est pas entre les mains de l'utilisateur dans un environnement d'exploitation différent.

Voilà à quoi ressemble la programmation procédurale.

L'orientation objet fournit un moyen de supprimer les hypothèses sur l'état des composants; ainsi, les opérations à effectuer sur ce composant et comment l'intégrer dans le produit final. En d'autres termes, OOP est comme prendre les détails du processus pour traiter un composant particulier et le confier à une machine plus petite. La plus grande machine responsable du processus indique à la machine spécifique au composant qui opération attendue, mais laisse les détails des étapes à la machine spécifique au composant à gérer.

Quant aux avantages de l’orientation objet par rapport aux logiciels non orientés objet:

  • comportement spécifique au composant - rendre les détails sur la façon de gérer un composant particulier sous la responsabilité de la machine spécifique au composant plus petit garantit que chaque fois que le composant est manipulé, sa machine le fera de manière appropriée;
  • expressions polymorphes - parce que les machines spécifiques à un composant effectuent des opérations adaptées à son composant particulier, le même message envoyé à différentes machines peut agir différemment;
  • type abstraction - il est souvent logique que plusieurs types de composants utilisent le même vocabulaire pour les opérations de leurs machines;
  • séparation des préoccupations - en laissant des détails spécifiques aux composants à leurs machines, la machine de traitement n'a besoin que de gérer les préoccupations plus générales et plus vastes de son processus et des données nécessaires à sa gestion; de plus, il est moins susceptible d'être affecté par des changements dans d'autres composants;
  • adaptabilité - les composants qui se concentrent sur leur domaine de spécialité peuvent être adaptés à une utilisation imprévue simplement en changeant les composants qu'ils utilisent ou en les mettant à la disposition d'une autre machine de traitement;
  • réutilisation de code - les composants avec une focalisation étroite et une plus grande adaptabilité peuvent tirer parti de leur coût de développement en étant plus souvent utilisés.
7
Huperniketes

À partir de votre blog, il semble que vous connaissiez à la fois la programmation impérative et fonctionnelle, et que vous connaissiez les concepts de base impliqués dans la programmation orientée objet, mais vous ne l'avez simplement jamais vraiment "cliqué" sur ce que le rend utile. Je vais essayer d'expliquer en termes de ces connaissances, et j'espère que cela vous sera utile.

À la base, OOP est un moyen d'utiliser le paradigme impératif pour mieux gérer des niveaux de complexité élevés en créant des structures de données "intelligentes" qui modélisent le domaine problématique. Dans un (non-objet procédural standard -oriented), vous avez deux choses fondamentales: les variables et le code qui sait quoi en faire. Le code prend les entrées de l'utilisateur et de diverses autres sources, les stocke dans des variables, les opère et produit des données de sortie qui va à l'utilisateur ou à divers autres emplacements.

La programmation orientée objet est un moyen de simplifier votre programme en prenant ce modèle de base et en le répétant à plus petite échelle. Tout comme un programme est une grande collection de données avec du code qui sait quoi en faire, chaque objet est un petit morceau de données lié au code qui sait quoi en faire.

En décomposant le domaine problématique en plus petits morceaux et en vous assurant que le plus de données possible est lié directement au code qui sait quoi en faire, vous simplifiez beaucoup le raisonnement sur le processus dans son ensemble et également sur le sous- questions qui composent le processus.

En regroupant les données dans des classes d'objets, vous pouvez centraliser le code lié à ces données, ce qui rend le code pertinent plus facile à trouver et à déboguer. Et en encapsulant les données derrière les spécificateurs d'accès et en n'y accédant que par des méthodes (ou des propriétés, si votre langue les prend en charge), vous réduisez considérablement le risque de corruption de données ou de violation d'invariants.

Et en utilisant l'héritage et le polymorphisme, vous pouvez réutiliser des classes préexistantes, en les personnalisant pour répondre à vos besoins spécifiques, sans avoir à modifier les originaux ou tout réécrire à partir de zéro. (Ce qui est une chose que vous ne devriez jamais faire , si vous pouvez l'éviter.) Faites juste attention à bien comprendre votre objet de base, ou vous pourriez vous retrouver avec kangourous tueurs .

Pour moi, ce sont les principes fondamentaux de la programmation orientée objet: gestion de la complexité, centralisation du code et modélisation améliorée du domaine de problèmes par la création de classes d'objets, l'héritage et le polymorphisme, et une sécurité accrue sans sacrifier le pouvoir ou le contrôle grâce à l'utilisation de l'encapsulation et Propriétés. J'espère que cela vous aidera à comprendre pourquoi tant de programmeurs le trouvent utile.

EDIT: En réponse à la question de Joel dans les commentaires,

Pouvez-vous expliquer ce qu'un "programme orienté objet" contient (à part ces définitions fantaisistes que vous avez décrites) qui est fondamentalement différent d'un programme impératif? Comment "lancez-vous la balle?"

Un petit avertissement ici. Mon modèle de "programme orienté objet" est fondamentalement le modèle Delphi, qui est très similaire au modèle C # /. NET puisqu'il a été créé par d'anciens membres de l'équipe Delphi. Ce que je dis ici peut ne pas s'appliquer, ou ne pas s'appliquer autant, dans d'autres OO langues.

Un programme orienté objet est un programme dans lequel toute la logique est structurée autour d'objets. Bien sûr, cela doit être amorcé quelque part. Votre programme Delphi typique contient du code d'initialisation qui crée un objet singleton appelé Application. Au début du programme, il appelle Application.Initialize, puis un appel à Application.CreateForm pour chaque formulaire que vous souhaitez charger en mémoire depuis le début, puis Application.Run, qui affiche le formulaire principal à l'écran et démarre la boucle d'entrée/événement qui constitue le cœur de tout programme informatique interactif.

L'application et vos formulaires interrogent les événements entrants du système d'exploitation et les traduisent en appels de méthode sur votre objet. Une chose très courante est l'utilisation de gestionnaires d'événements, ou "délégués" en langage .NET. Un objet a une méthode qui dit "faites X et Y, mais vérifiez également si ce gestionnaire d'événement particulier est affecté et appelez-le si c'est le cas". Un gestionnaire d'événements est un pointeur de méthode - une fermeture très simple qui contient une référence à la méthode et une référence à l'instance d'objet - qui est utilisé pour étendre le comportement des objets. Par exemple, si j'ai un objet bouton sur mon formulaire, je personnalise son comportement en attachant un gestionnaire d'événements OnClick, ce qui oblige un autre objet à exécuter une méthode lorsque le bouton est cliqué.

Ainsi, dans un programme orienté objet, la plupart du travail se fait en définissant des objets avec certaines responsabilités et en les reliant, soit par des pointeurs de méthode, soit par un objet appelant directement une méthode définie dans l'interface publique d'un autre objet. (Et maintenant, nous sommes de retour à l'encapsulation.) C'est une idée que je n'avais aucune idée du dos avant de prendre des cours OOP au collège).

46
Mason Wheeler

Je pense que OOP est fondamentalement juste un nom donné à quelque chose que vous pourriez avoir été tenté de faire en cours de route, comme je l'ai été.

Il y a très longtemps, quand j'étais bébé programmeur, même à Fortran, il y avait un pointeur vers un sous-programme. Il est vraiment utile de pouvoir passer un pointeur à un sous-programme comme argument à un autre sous-programme.

Ensuite, la prochaine chose qui serait vraiment utile serait de stocker un pointeur vers un sous-programme à l'intérieur d'un enregistrement d'une structure de données. De cette façon, vous pourriez dire que l'enregistrement "sait" comment effectuer des opérations sur lui-même.

Je ne sais pas s'ils ont déjà intégré cela à Fortran, mais c'est facile à faire dans C et ses descendants.

Donc, en dessous, c'est une idée simple et utile que vous pourriez avoir été tenté de faire vous-même, et c'est plus facile à faire dans des langues plus récentes, même si certaines personnes l'ont transformé en un train géant plein de mots à la mode effrayants.

6
Mike Dunlavey

Il existe différents types de systèmes OO, et il est difficile d'obtenir une définition sur laquelle tout le monde sera d'accord. Plutôt que d'essayer de montrer en quoi Java OO est similaire au Common LISP Object System, je vais commencer par quelque chose de plus conventionnel, étape par étape.

Supposons que de nombreux objets existent sous forme de données dispersées. Les points, par exemple, peuvent être des éléments d'un tableau X, Y et Z. Pour considérer un point lui-même, il est logique de rassembler toutes les données en quelque chose comme un C struct.

Maintenant, pour tout objet de données, nous avons toutes les données ensemble. Cependant, dans un programme procédural, le code est dispersé. Supposons que nous ayons affaire à des formes géométriques. Il y a une grande fonction pour dessiner des formes, et il doit connaître toutes les formes. Il y a une grande fonction pour trouver la zone et une autre pour le périmètre. Le code d'un cercle est dispersé à travers plusieurs fonctions, et pour ajouter un autre type de forme, nous devons savoir quelles fonctions changer. Dans un système orienté objet, nous rassemblons les fonctions dans le même genre de chose (class) que les données. Par conséquent, si nous voulons regarder tout le code du cercle, il est là dans la définition Circle, et si nous voulons ajouter un Quartercircle nous écrivons simplement sa classe et nous avons le code .

Un avantage secondaire de ceci est que nous pouvons maintenir des invariants de classe, des choses qui sont vraies à propos de chaque membre de la classe. En empêchant le code en dehors de la classe de jouer directement avec les membres des données de classe, nous avons tout le code qui peut changer les données de classe en un seul endroit, et nous pouvons confirmer qu'il ne fait rien de compliqué (comme avoir un triangle avec une jambe) plus longtemps que les deux autres combinés). Cela signifie que nous pouvons compter sur certaines propriétés de chaque membre de la classe et ne pas avoir à vérifier si un objet est sain à chaque fois que nous l'utilisons.

Le principal avantage vient de l'héritage et du polymorphisme. En définissant toutes ces différentes formes comme des sous-classes d'une classe appelée Shape, nous pouvons faire manipuler notre code Shapes, et c'est le travail des sous-objets de forme de faire tout ce que les manipulations demandent. . Cela signifie que nous n'avons pas besoin de toucher à l'ancien code testé lorsque nous ajoutons de nouvelles formes ou affinons le comportement des anciennes. Nous avons automatiquement un ancien code qui peut directement profiter du nouveau code. Au lieu de rendre le code de contrôle conscient de toutes les différentes formes possibles et d'avoir à maintenir des fonctions qui connaissent toutes les différentes formes possibles, nous traitons simplement les formes et leurs propriétés, tout en conservant les sous-classes Shape. Cela simplifie le code de contrôle.

Nous avons ici plusieurs avantages. Étant donné que nous avons des invariants de classe, nous pouvons raisonner sur les objets de données plus gros de la même manière que nous raisonnons sur les types intégrés, ce qui signifie que nous pouvons souvent diviser des concepts complexes en concepts plus simples. Puisque le code du cercle est largement contenu dans Circle, nous avons augmenté la localité. Puisqu'il n'y a pas de concepts de cercle dispersés à travers plusieurs fonctions différentes à différents endroits, nous obtenons moins de couplage entre les routines et n'avons pas à nous soucier de les garder synchronisés. Étant donné que les classes sont en fait des types, nous pouvons tirer parti du système de types existant pour détecter une utilisation incompatible de nos classes.

5
David Thornley

OO a de nombreuses définitions différentes, oui. Je suis sûr que vous pouvez en trouver beaucoup par vous-même. Personnellement, j'aime Rees Re: OO comme un moyen de leur donner un sens. Je suppose que vous l'avez déjà lu depuis que vous citez Paul Graham. (Je le recommande à toute personne intéressée par l'OO.) Je vais plus ou moins adopter la définition Java ici {1,2,3,7,8,9}.

La question de l'utilité de l'OO, en particulier la façon dont je l'aborde, mérite une réponse beaucoup plus large avec quelques milliers de lignes de code (en partie pour ne pas être juste un tas d'assertions). Cependant, voici un résumé de ce document hypothétique.

Je ne pense pas que OO soit terriblement utile à petite échelle, disons environ quelques centaines de lignes. En particulier, les langues OO sans bonnes influences fonctionnelles ont tendance pour rendre vraiment difficile de faire des choses simples avec tout type de collection ou tout ce qui nécessite de nombreux types de données. C'est là que la plupart des modèles de conception entrent en jeu; ce sont des pansements sur la faible puissance du sous-jacent langue .

À environ un millier de lignes, il devient plus difficile de garder une trace de toutes les opérations et structures de données et de la façon dont elles sont liées. Il est utile, à ce stade, d'avoir un moyen d'organiser explicitement les structures de données et les opérations, de dessiner les limites des modules et de définir les responsabilités, et d'avoir un moyen pratique de comprendre ces définitions pendant que vous essayez de les programmer.

Java-ish OO est une solution à mi-chemin à ces problèmes qui se trouve avoir remporté le concours de popularité. Parce que c'est le même mécanisme que Java les gens s'appliquent au petit) problèmes d'échelle créés par un langage sous-alimenté, il a tendance à ressembler davantage à une solution magique à tout qu'à un simple moyen de rester organisé. coincé en C++, ou bien (comme moi, travaillant quotidiennement en C #) utilisez OO mais ne vous excitez pas du tout.

3
Jesse Millikan

POO = structures de données + passage de message + héritage, qui sont tous des évolutions logiques dans les modèles de programmation.

La POO peut être comprise (par les programmeurs) en environ 90 secondes (voir mon profil pour un lien). Les concepts sont très simples.

Comment l'appliquer est une autre affaire. Ce n'est pas parce que vous savez comment balancer un marteau que vous savez comment concevoir et construire une maison. ;-)

1
Steven A. Lowe

La POO tente de modéliser des concepts du monde réel en termes d'objets et d'interactions entre eux. En tant qu'êtres humains, nous avons tendance à traiter le monde en termes d'objets. Le monde est plein d'objets qui ont certaines propriétés et peuvent faire des choses comme interagir avec d'autres objets. OOP permet de modéliser le monde en termes similaires. Par exemple,

  • La personne est un objet. Une personne a certaines propriétés, comme l'âge et le sexe. Une personne peut faire des choses: manger, dormir, conduire une voiture.
  • La voiture est également un objet (bien que de type différent). Il possède également des propriétés telles que la marque, le modèle et l'année. Une voiture peut faire des choses: bouger.

Mais une voiture ne peut pas se déplacer seule, elle a besoin d'une personne pour la conduire - interaction entre les objets.

1
ysolik

Puisque vous comprenez les structures, et que vous comprenez les pointeurs de fonction, et que vous comprenez les structures avec des pointeurs de fonction, de votre point de vue, je définirais la programmation orientée objet comme une simple "programmation, avec une utilisation intensive de structures qui ont des pointeurs de fonction". C'est toujours de la programmation au sens traditionnel - ce sont toutes les données et le code qui agissent sur les données. La différence réside simplement dans la manière dont toutes ces informations sont définies et dans la façon dont vous les définissez.

Une simplification excessive est peut-être que la programmation traditionnelle est "du code, avec certaines structures de données", et la programmation orientée objet est "des structures de données, avec du code". Les deux ont toujours des structures de données, et les deux ont toujours du code. La programmation orientée objet n'est alors rien de plus que l'acte de définir des types de données à l'avance et d'appliquer des contrats pour la façon dont ils communiquent via des ensembles de fonctions.

Comme vous l'avez observé, il existe une énorme classe d'applications pour lesquelles ce n'est pas un excellent moyen de mettre en œuvre une solution. Vous semblez vivre dans un monde principalement composé de telles applications. Dans votre article de blog, vous mentionnez regarder les implémentations du problème "99 bouteilles de bière" (votre "vitrine de programmation préférée"). 99 bouteilles de bière font certainement partie de cette catégorie. Essayer de comprendre la programmation orientée objet en regardant les implémentations de 99 bouteilles de bière, c'est un peu comme essayer de comprendre l'architecture de grande hauteur en regardant une cabane dans les arbres. Même une cabane dans les arbres très bien construite ne peut que vous apprendre beaucoup.

TL; DR: OO la programmation est comme la programmation traditionnelle, sauf que vous concentrez davantage vos efforts sur la définition des structures de données à l'avance et que ces structures de données communiquent entre elles via des pointeurs de fonction.

0
Bryan Oakley

Voici comment je l'ai compris pour la première fois:

Avant la programmation orientée objet, vous aviez Programmation structurée . Tout est centré sur le processus. La première question que vous devez vous poser est " Qu'est-ce que je veux faire avec les informations? ".

Avec la programmation orientée objet, elle est centrée sur les données. La première question que vous devez vous poser est " Informations sur la sorcière dont je dois traiter? ". Cela facilite l'abstraction.

0
DavRob60

J'ai écrit un article de blog il y a quelque temps que vous pourriez trouver utile: Procédure vs OOP Explained .

0
VirtuosiMedia