Comment la POO a-t-elle évolué pour inclure la notion de propriétés

12

Je viens d'un milieu C ++ et je fais tout C # dans mon travail actuel et je viens de lire beaucoup de questions et réponses sur la différence entre les champs publics et les propriétés et tous les va-et-vient dans les variations et les incarnations de ce question de base (par exemple, ce message SO et toutes les questions connexes liées ). Toutes ces questions sont abordées en termes de différences pratiques qui tiennent pour acquis l'existence d'un système de propriété, mais je pense qu'il serait bon d'aborder ce sujet en termes de ce que les concepteurs de toutes les langues qui ont décidé de soutenir les propriétés dans le premier l'endroit pensait (consultez la liste dans l'article Wikipedia ici). Comment la POO a évolué du C ++ / Java pour s'étendre dans ce que l'article de Wikipedia identifie de manière intéressante comme un milieu entre les méthodes et les données des membres:

"Autrement dit, les propriétés sont intermédiaires entre le code membre (méthodes) et les données membres (variables d'instance) de la classe, et les propriétés fournissent un niveau d'encapsulation plus élevé que les champs publics."

MSDN ajoute des informations supplémentaires:

"Bien que les propriétés soient techniquement très similaires aux méthodes, elles sont très différentes en termes de scénarios d'utilisation. Elles doivent être considérées comme des champs intelligents. Elles ont la syntaxe d'appel des champs et la flexibilité des méthodes."

J'aimerais savoir comment on en est arrivé à ce que ce niveau intermédiaire d'encapsulation s'est avéré utile pour la programmation en général. Je suppose que ce concept n'était pas présent lors de la première incarnation des langages de programmation qui exprimaient le paradigme OOP.

jxramos
la source
8
La fonction de langage nu est juste un sucre syntaxique pratique pour les méthodes getter et setter. S'il y a des raisons plus profondes derrière l'interprétation et la terminologie, je ne sais pas.
Dans une ronde d'experts OO, le titre de votre question peut être provocant et peut distraire de ce que vous demandiez vraiment. Non pas que je me considère comme un expert OO, je suis juste un "utilisateur OO" depuis plusieurs années.
Doc Brown
C'est une subtilité syntaxique qui me manque de passer des «méthodes sans paramètres» en Python au C ++. BMI = bob.weight/sq(bob.height)lit mieux sans ()IMO.
OJFord
Je pense que les propriétés étaient dans le Visual Basic d'origine (non .net), comme un moyen de configurer l'objet Active X (COM). La grille de propriétés de cet outil avait probablement quelque chose à voir avec l'adoption de propriétés dans les langues. Notez que le Visual Basic d'origine n'était pas orienté objet à bien des égards, mais il avait la capacité de créer quelque chose comme des classes.
Frank Hileman
Continuation: la fenêtre de propriétés était un moyen de configurer des objets sans écrire de code. Cela s'appelait développement RAD. Ce lien contient une capture d'écran de la fenêtre des propriétés VB6: microsoft.com/mspress/books/WW/sampchap/4068.aspx
Frank Hileman

Réponses:

5

Il s'agit de l'encapsulation et du principe d'accès uniforme.

Un objet doit être en mesure de répondre à un message en renvoyant des données existantes ou en exécutant une méthode, mais l'expéditeur ne doit pas être en mesure de dire laquelle est laquelle. Ou si vous voyez cela du côté de l'expéditeur: l'expéditeur doit pouvoir accéder aux données existantes ou exécuter une méthode via une interface uniforme.

Il existe plusieurs façons d'y parvenir:

  • se débarrasser complètement des données, il suffit d'avoir des méthodes (Newspeak le fait)

    • une forme moins radicale de ce qui précède: se débarrasser des données dans l'interface publique , c'est-à-dire rendre les données toujours privées, dans l'interface publique, exposer uniquement les méthodes (Smalltalk, Ruby le font)
  • se débarrasser complètement des méthodes, juste avoir des données (Self fait cela, les "méthodes" ne sont que des Methodobjets affectés aux variables d'instance, les variables d'instance sont recherchées avec une répartition virtuelle)

  • ne pas faire de distinction syntaxique ou sémantique entre les méthodes et les données (Scala le fait, l'accès à un champ est impossible à distinguer syntaxiquement d'appeler une méthode sans liste d'arguments ( foo.bar), l'affectation à un champ est impossible à distinguer syntaxiquement d'appeler une méthode spécialement nommée ( foo.bar = baz) est la même comme foo.bar_=(baz)c'est- à- dire appeler une méthode nommée foo_=, et les valeurs en lecture seule peuvent être écrasées ou implémentées par une méthode sans liste de paramètres (ie val foo) dans une superclasse peuvent être écrasées (ou abstract valêtre implémentées) dans une sous-classe avec une méthode def foo)

Java, cependant, ne suit pas le principe d'accès uniforme. En Java, il est possible de distinguer entre l'accès aux données et l'exécution d'une méthode. foo.barest différent de foo.bar(). La raison en est que les champs et les méthodes sont sémantiquement et syntaxiquement distincts.

C # essaie de résoudre ce problème en ajoutant des propriétés au langage, essentiellement des méthodes qui ressemblent à des champs. Cependant, les appels de méthode sont toujours différents des accès aux champs et aux propriétés. Les champs et les propriétés ont désormais un accès uniforme, mais pas les méthodes.

Donc, cela ne résout pas réellement le problème: vous ne pouvez pas résoudre deux façons différentes d'accéder aux choses en ajoutant une troisième façon d'accéder aux choses! Même si cette troisième voie ressemble à l'une des deux autres façons, vous aurez toujours (au moins) deux façons différentes. Vous ne pouvez le corriger qu'en vous débarrassant de toutes les différentes manières sauf une ou en supprimant les différences.

C'est parfaitement bien d'avoir un langage avec des méthodes, des propriétés et des champs, mais les trois devraient avoir un accès uniforme.

Jörg W Mittag
la source
1
Pourquoi pensez-vous (et d'autres) que le maintien de l'accès uniforme est si important? Avec une méthode, vous voudrez peut-être lui donner des paramètres pour changer son action ou son action. Avec un champ ou une propriété que vous ne possédez pas, vous retournez généralement des données (bien qu'une propriété puisse être implémentée comme exécutant une méthode au lieu d'exposer simplement un champ privé). Cela me semble intuitif, peut-être simplement parce que j'y suis habitué, mais que gagneriez-vous en élégance ou en productivité en imposant un accès uniforme? Avez-vous peur de divulguer des détails d'implémentation en dehors de la classe?
Mike prend en charge Monica
1
L'UAP consiste à se réserver la liberté de modifier les détails d'implémentation sans rompre l'interface publique. L'exemple habituel est l'ajout de journalisation. Si j'offre un accès via une méthode, je peux modifier de manière triviale les éléments internes de la méthode pour écrire dans un journal. Avec un champ public, je ne peux pas ajouter la journalisation sans d'abord la transformer en une méthode qui casse tout le code client. Si la rupture des changements ne peut pas être risquée, l'utilisation de méthodes est indispensable. Les propriétés sont le compromis optimal car ce sont des méthodes complètes mais ressemblent à des champs. L'adhésion à l'UAP améliore l'encapsulation et réduit le couplage serré.
amon
Beaucoup de bonnes réponses à cette question, mais je pense que celle-ci a mis le doigt sur la tête en retirant les aspects les plus fondamentaux de la nature des langages de programmation et en développant le concept formel pertinent de l'UAP. Solid
jxramos
18

Eh bien, je ne suis pas sûr à 100%, mais je suppose que les choses sont probablement plus simples que vous ne le pensez. Depuis les écoles de modélisation OO des années 90, il y avait une demande pour des classes de modélisation avec des attributs de membre encapsulés, et lorsqu'elles sont implémentées dans des langages comme C ++ ou Java, cela conduit généralement à du code avec beaucoup de getters et setters, donc beaucoup de «bruit» code pour une exigence relativement simple. Notez que la plupart (probablement tous, n'ont pas vérifié cela) les langues répertoriées dans votre article Wikipedia lié ont commencé à introduire des «propriétés» des objets à la fin des années 90 ou plus tard.

Je suppose que c'est la principale raison pour laquelle les concepteurs de langage ont décidé d'ajouter du sucre syntaxique pour réduire ce bruit. Et bien que les propriétés ne soient sûrement pas un «concept OO de base», elles ont au moins quelque chose à voir avec l'orientation des objets. Ils ne montrent pas "une évolution de la POO" (comme le suppose le titre de votre question), mais ils prennent en charge la modélisation OO au niveau du langage de programmation pour faciliter la mise en œuvre.

Doc Brown
la source
Cela n'a rien à voir avec la programmation orientée objet, sauf dans le sens où une propriété est l'abstraction d'un champ, et les champs font partie de la programmation orientée objet. Mais les propriétés ne sont pas nécessaires pour la programmation orientée objet, comme vous le constatez correctement.
Frank Hileman
2
@FrankHileman: « une propriété est une abstraction d'un champ et les champs font partie de la programmation orientée objet » - bien que des sons à moi comme vous d' accord le concept a fait au moins quelque chose à voir avec la POO. Et c'est pour ça que tu m'as déçu?
Doc Brown
3
lol. Pouvez-vous lui en vouloir? Il a glissé de ses toilettes et s'est cogné la tête contre son évier. Quoi qu'il en soit ... La façon dont je l'ai toujours vu, c'est que les propriétés ne sont pas strictement liées à l'OO. Ils aident à l'encapsulation et l'encapsulation aide à OO.
MetaFight
1
Ha! C'est tout à fait l'introduction à programmers.stackexchange pour moi. Lol, beaucoup plus chauffé que mon expérience équivalente dans plain ol stackoverflow :-p Bon moyen de mélanger la journée!
jxramos
11

Vous l'avez à l'envers (en quelque sorte). Lambda Calculus existe à peu près comme la base formelle de base pour les langages de programmation, et ce depuis des décennies. Il n'a pas de champs.

Pour modéliser l'état mutable, vous devez effectuer deux abstractions. L'un représente la définition d'un état, et un autre qui récupère cet état (chapitre 13 dans ma version de TaPL pour référence). Semble familier? D'un fond théorique , OO n'a pas évolué pour avoir ce genre de choses. OO a lu les langages de programmation 101 et a fait un petit pas en avant.

D'un point de vue pratique , il existe deux motivations assez claires. Vous venez d'un arrière-plan C ++, alors que devrait-il se passer si vous aviez un champ public - disons ... le texte dans une zone de texte. Que se passe-t-il lorsque vous souhaitez modifier votre conception afin que "chaque fois que cette zone de texte change, faites bof"? Vous pouvez tuer ce champ, créer une fonction ou deux et câbler cette logique, car vous ne pouvez pas faire confiance aux développeurs pour appeler eux-mêmes "UpdateTextbox". Il s'agit d'un changement très important dans votre API (et malheureusement encore un changement majeur dans l'implémentation des propriétés de .NET). Ce type de comportement est partout dans l'API Windows. Étant donné que c'est un gros problème chez Microsoft, C # voulait probablement rendre cela moins douloureux.

L'autre grande motivation est Java Beans et leurs proches. Un certain nombre de cadres ont été construits pour utiliser la réflexion Java pour rechercher GetXet SetXassocier et les traiter efficacement comme des propriétés modernes. Mais comme il ne s'agissait pas de véritables constructions de langage, ces cadres étaient fragiles et peu familiers. Si vous tapiez un nom, les choses se briseraient silencieusement. Si l'un a été refactorisé, rien ne bouge de l'autre côté de la propriété. Et faire tout le passe-partout field / get / set était bavard et fastidieux (même pour Java!). Depuis que C # a été développé en grande partie comme "Java avec leçons apprises", ce genre de douleur était l'une de ces leçons.

Mais le plus gros, c'est que le concept immobilier a réussi. C'est facile à comprendre, c'est facile à utiliser. Celles-ci facilitent grandement l'adoption et, en tant qu'outil , les programmeurs ont constaté que les propriétés résolvent un sous-ensemble de problèmes plus proprement que les fonctions ou les champs.

Telastyn
la source
7
Je vous ai voté principalement pour trop de référence à la merde formelle non pertinente. Les implémentations réelles des langages de programmation ont des choses beaucoup plus sérieuses à considérer que si leur modèle a été inclus ou non dans le calcul lambda.
DeadMG
9
@DeadMG - c'est certainement vrai, mais d'un autre côté, les implémenteurs de langage de programmation vont toujours se familiariser avec cette merde formelle non pertinente . Penser que cela n'a pas eu d'impact sur leurs conceptions est naïf.
Telastyn
3
Ce n'est certainement pas une «merde formelle non pertinente». Cependant, le calcul lambda peut ne pas avoir été beaucoup considéré pour les premiers langages de programmation. Si c'est le cas, les processeurs seraient probablement plus orientés vers cette mentalité.
Frank Hileman
3
@FrankHileman - Je suis presque sûr que Lisp y a pensé ...
Telastyn
4
@Telastyn - oui - et Lisp n'était pas censé être un langage de programmation à l'origine, tu te souviens?
Frank Hileman
3

Dans .net en particulier, les propriétés proviennent des anciens jours Visual Basic qui, en l'occurrence, n'étaient pas orientés objet dans la façon dont nous y pensons aujourd'hui. Il a été largement construit autour du système COM alors nouveau qui superficiellement traitait tout non pas nécessairement comme des classes mais en termes de composants qui exposeraient des propriétés accessibles à la fois dans le code mais aussi dans les éditeurs graphiques. Lorsque VB et le C # nouvellement créé ont été fusionnés dans .net, VB a gagné beaucoup de fonctionnalités OOP et ils ont conservé les propriétés car les supprimer serait comme un pas en arrière - imaginez si l'outil de mise à jour automatique du code qu'ils avaient dans Visual Studio avait été remplacer toutes vos propriétés par des getters et des setters et rompait la compatibilité avec toutes les bibliothèques COM. Il serait logique de les soutenir en tout.

niwax
la source
Je ne pense pas que vous devriez ignorer l'ascendance de C # qui est venue de Delphi et d'avant cela, Object Pascal et Turbo Pascal avec Objects. Celles-ci étaient orientées objet et avaient des propriétés (même si je ne me souviens pas si OP avait des propriétés de TP5.5 ou si elles ont été ajoutées; on suppose qu'elles ont été continuées en C # par Anders parce qu'elles étaient pragmatiquement une bonne idée.
amaca
Très intéressant que vous soyez le seul à avoir abordé l'aspect composant cette question. Je viens d'ajouter un commentaire à ma question en créant un lien vers un site qui répertorie les propriétés dans le cadre d'un modèle d'événement de méthode de propriété que C # satisfait. J'ai ensuite recherché à nouveau la page de ma question pour "composant" atterrissant quelques faux positifs, mais je pense que votre réponse chevauche en fait avec ce que j'ai lié.
jxramos
3

Les propriétés n'ont rien à voir avec la programmation orientée objet, car les propriétés ne sont que du sucre syntaxique. Les propriétés ressemblent à des champs superficiellement, et dans le monde .net, il est recommandé qu'elles se comportent comme des champs à certains égards, mais ce ne sont en aucun cas des champs. Les propriétés sont du sucre syntaxique pour une ou deux méthodes: une pour obtenir une valeur et une pour définir une valeur. La méthode set ou la méthode get peut être omise, mais pas les deux. Il se peut qu'aucun champ ne stocke la valeur renvoyée par la méthode get. Parce qu'ils partagent une syntaxe avec les champs et qu'ils utilisent souvent des champs, les gens associent des propriétés aux champs.

Les propriétés ont des avantages sur les champs:

  • Dans une méthode de jeu de propriétés, avant qu'une valeur de propriété ne soit stockée, la nouvelle valeur, ou l'état de l'objet, peut être comparé à un ensemble de conditions préalables ou d'invariants.
  • Une méthode d'obtention de propriété peut exister pour des raisons de commodité, si la récupération de la valeur de la propriété peut logiquement être considérée comme équivalente à la récupération d'une valeur de champ.
  • Une méthode de jeu de propriétés peut effectuer d'autres opérations, comme notifier un objet parent ou écouter des objets d'une modification d'une valeur de propriété.

Étant donné que les propriétés sont l'abstraction des champs et pour des raisons de syntaxe, des langages tels que C # ont adopté la syntaxe des champs pour les propriétés.

Frank Hileman
la source
2
Première ligne de l'article Wikipedia. Msgstr "Une propriété, dans certains langages de programmation orientés objet, est une sorte spéciale de membre de classe ...". Votre première phrase est donc tout à fait fausse. Et la partie restante ne répond pas à la question.
Doc Brown
1
@DocBrown: Réponse intéressante. De nombreux articles Wikipedia sont clairement incorrects. Je suppose que vous défendez l'auteur de cet article spécifique?
Frank Hileman
1
Toutes les fonctionnalités des langages de programmation orientés objet ne sont pas liées aux concepts orientés objet.
Frank Hileman
1
Cela ne change rien au fait que vous ne répondez pas à la question.
Doc Brown
3
Il convient de noter que ce n'est pas seulement le setter qui est facultatif. Vous pouvez avoir des propriétés de setter uniquement.
Telastyn
2

C'est une question d' implémentation versus d' implication . Les propriétés étaient en POO avant que C ++ ou Java n'entrent en scène (elles étaient là, avec une certaine rugosité autour des bords, dans Simula, et elles sont fondamentales pour Smalltalk). Les entités avec des propriétés sont conceptuellement différentes des valeurs avec du code attaché. Les préfixes get & set dans certaines conventions linguistiques ne servent qu'à brouiller les eaux; ils vous font prendre conscience de la différence entre les champs et les propriétés, en supposant que les champs peuvent être accédés directement sans get / set d'une manière idiomatique à la langue, et c'est une fuite.

Le but de la POO est de traiter les choses comme si elles étaient des entités dans le monde "réel", pas seulement comme des structures avec du code mélangé. Un autre programmeur devrait avoir besoin de savoir très, très peu de choses sur la façon dont j'ai implémenté les choses, et ne devrait pas du tout se préoccuper de laquelle des différentes valeurs qu’elles sont autorisées à obtenir et / ou définir sont réelles et lesquelles sont virtuelles. Si vous rencontrez un de mes vecteurs, vous ne devriez pas avoir besoin de savoir si je stocke l'angle et la magnitude ou des composants réels et imaginaires internes à l'objet vectoriel. Si je change la représentation dans la version 2.0 de ma bibliothèque, cela ne devrait pas du tout affecter votre code (bien que vous souhaitiez peut-être profiter des nouvelles fonctionnalités intéressantes). De même, certaines entités peuvent avoir des propriétés qui dépendent de données externes à l'entité, mais qui sont sans aucun doute des propriétés d'un point de vue lexical. Vous demandez aux gens "quel âge avez-vous", pas "veuillez effectuer le calcul qui me révélera votre âge", même si vous savez que les données disponibles pour cet "objet" sont la date de naissance (un membre privé immuable) et celle d'aujourd'hui date (propriété environnementale publique à incrémentation automatique, dépendante du fuseau horaire, de l'heure d'été et de la ligne de date internationale). L'âge est une propriété, pas une méthode, même s'il faut un certain calcul pour y arriver et ne peut pas (sauf dans les représentations par ordinateur jouet d'objets avec des durées de vie artificiellement limitées) être stocké comme un champ. même si vous savez que les données disponibles pour cet "objet" sont la date de naissance (un membre privé immuable) et la date d'aujourd'hui (une propriété environnementale publique à incrémentation automatique, en fonction du fuseau horaire, de l'heure d'été et de la ligne de date internationale ). L'âge est une propriété, pas une méthode, même s'il faut un certain calcul pour y arriver et ne peut pas (sauf dans les représentations par ordinateur jouet d'objets avec des durées de vie artificiellement limitées) être stocké comme un champ. même si vous savez que les données disponibles pour cet "objet" sont la date de naissance (un membre privé immuable) et la date d'aujourd'hui (une propriété environnementale publique à incrémentation automatique, en fonction du fuseau horaire, de l'heure d'été et de la ligne de date internationale ). L'âge est une propriété, pas une méthode, même s'il faut un certain calcul pour y arriver et ne peut pas (sauf dans les représentations par ordinateur jouet d'objets avec des durées de vie artificiellement limitées) être stocké comme un champ.

Plutôt que de considérer les propriétés comme l'enfant bâtard des champs et des méthodes, c'est beaucoup plus satisfaisant que les méthodes comme une sorte de propriété spécialisée - des choses que vos entités peuvent faire plutôt que des choses qu'elles sont. Sinon, vous ne traitez pas conceptuellement avec des objets / entités, vous traitez avec des collections de données auxquelles du code est attaché. Les implémentations peuvent être identiques, mais les implications sont différentes.

Il va sans dire, cependant, que cette abstraction a un coût. Si un programmeur utilisant une classe ne peut pas dire s'il accède aux données telles qu'elles sont stockées ou obtient / définit des valeurs qui doivent être calculées, alors il y aura un niveau auquel le langage est également nécessairement incertain (et peut donc exiger que tout nécessite un code intermédiaire entre les accesseurs / sélecteurs et les valeurs). Il n'y a rien de mal conceptuellement avec les "structures avec du code" - elles peuvent certainement être beaucoup plus efficaces - mais elles fuient l'implémentation partout, et c'est l'une des choses que la POO est censée éliminer.

Stan Rogers
la source
Je suis d' accord avec certains points et en désaccord avec les autres, mais le message global est un bon: Quelques informations sur un objet besoins à calculer , mais est toujours l' information sur le plan technique qui est plutôt que d' une action qui peut être fait .
Pharap
0

Absolument rien du tout. Les propriétés et la POO n'ont rien à voir les unes avec les autres. Les propriétés ne sont rien de plus que du sucre syntaxique pour les appels de fonction, et ont donc exactement le même attachement OOP que les appels de fonction font, c'est-à-dire aucun.

Soit dit en passant, Wikipedia est complètement incorrect. Le modèle getMember / setMember que vous voyez en Java offre exactement les mêmes avantages (et inconvénients) que les propriétés en C #. Et vous pouvez reproduire ce modèle même en C si vous le souhaitez.

Les propriétés en C # ne sont rien d'autre que du sucre syntaxique supporté par le langage.

DeadMG
la source
3
Avez-vous déjà vu le concept de propriété dans un langage de programmation en dehors d'un contexte de classe ou d'objet? Je n'ai pas.
Doc Brown
1
@DocBrown: je l'ai implémenté. Le fait est que les propriétés sont des cibles assez faibles pour les auteurs de langage, car leur amélioration par rapport aux appels de fonction réguliers est faible.
DeadMG
1
OP se posait des questions sur l' histoire des propriétés en tant que concept dans les langages de programmation populaires. Et en fait, au sens historique, il existe un lien entre les propriétés et la POO.
Doc Brown
2
J'ai peut-être été un peu téméraire d'attribuer ce concept de propriétés au paradigme de la POO en soi, mais en tant que concept, il transcende certainement les langages individuels et leurs caractéristiques. Peut-être que j'ai du mal à articuler l'ontologie appropriée entre les deux. Je ne suggère pas à travers le titre de la question que les propriétés sont une caractéristique / un concept fondamental de la POO qui fait ou casse le formalisme de la POO, et pourtant je sens qu'ils n'ont qu'une réalité dans cet espace de POO, c'est pourquoi j'ai formulé la question comme telle .
jxramos
4
Ils ne sont pas seulement du sucre de syntaxe en C #, ils existent dans les métadonnées d'assembly en tant que membres distincts et vous pouvez faire des choses avec des propriétés que vous ne pouvez pas avec des champs, comme la liaison de données.
Andy