web-dev-qa-db-fra.com

Dans la POO, le mot clé «protégé» n'est-il pas requis?

Certaines langues modernes (par exemple Swift, Dart) ne prennent pas en charge le mot-clé modificateur d'accès protected. Swift est un langage orienté protocole, mais j'ai entendu dire que Dart est un langage entièrement orienté objet.

Pourquoi ces langues modernes ne prennent-elles pas en charge protected? Avez-vous seulement besoin de private et public pour une programmation orientée objet complète?

Je pense qu'il est pratique d'avoir un mot-clé modificateur d'accès protected lorsqu'il y a des données ou des interfaces que je veux passer de la classe parent à la classe enfant. Pourquoi certaines langues modernes ne prennent-elles pas en charge protected?

28
ShutUpILoveYou

Cela dépend de ce que vous entendez par "requis".

Les modificateurs d'accès ne sont pas une nécessité. Vous pouvez remplacer chaque modificateur d'accès par public et la plupart des applications fonctionneront comme elles le faisaient lorsque vous utilisiez divers modificateurs d'accès, prouvant ainsi que l'objectif principal du compilateur (sortie d'une application qui fonctionne) ne dépend pas directement des modificateurs d'accès .

Comme Delioth l'a mentionné dans les commentaires, Javascript et Python sont capables de OOP n'ont pas encore de concept de modificateurs d'accès; ce qui prouve que = OOP ne nécessite pas de modificateurs d'accès.

Cependant, les modificateurs d'accès sont très importants du point de vue du développeur si vous souhaitez éviter les erreurs. Le manque de restrictions d'accès conduit les développeurs à accéder directement aux dépendances qu'ils ne devraient pas (par exemple contourner une couche de validation/autorisation), ce qui entraînera des bogues, ce qui entraînera du temps et des efforts.

En conclusion, les modificateurs d'accès ne sont pas requis pour le compilateur, mais ils sont généralement considérés comme très agréables à utiliser. De telles directives "obligent" les développeurs à exercer un contrôle d'accès diligent - même si le compilateur n'en a pas besoin.

Pourquoi certaines langues modernes suppriment le protected?

Il n'y a pas de réponse universellement applicable à cette question, si ce n'est "parce que c'est ce que les concepteurs de langage ont décidé de faire".

45
Flater

Non, ce n'est pas obligatoire: Bjarne Stroustrup, expliqué comment il a naïvement ajouté protected à C++ version 1.2, pensant fournir une fonctionnalité utile aux développeurs de classe, juste pour conclure seulement 5 ans plus tard que c'était une source désagréable de bugs, que personne n'a heureusement été obligé d'utiliser. De nos jours, il recommande de ne pas l'utiliser .

Les arguments pratiques contre protected sont les avantages d'une encapsulation plus forte et le principe de la moindre connaissance :

  • Soit un membre est public et peut être utilisé par n'importe qui;
  • Ou le membre est private et doit être protégé contre les accès externes.
  • Un membre protected, qui nécessite une utilisation prudente (sinon il serait public) peut être utilisé à mauvais escient autant par les initiés (développeurs de classe dérivée) que par n'importe qui d'autre.

Des arguments formels confirment l'expérience pratique. Cela a à voir avec le principe de substitution de Liskov et plus précisément sa règle d'histoire:

Nous pensons qu'il devrait être suffisant pour un utilisateur de ne connaître que le type "apparent" de l'objet; le sous-type doit conserver toutes les propriétés qui peuvent être prouvées sur le supertype.
- Barbara Liskov & Jeanette Wing dans Une notion comportementale du sous-typage

Sans entrer dans les détails de l'article cité, les membres protégés permettent à une classe dérivée (sous-type) de modifier l'état de l'objet de classe de base (supertype) de manière inattendue, sans se fier à ses opérations publiques.

Cela dit, méfiez-vous des apparences et des fausses promesses. Le Swift private est entre private et protected dans d'autres langues:

L'accès privé limite l'utilisation d'une entité à la déclaration englobante, et aux extensions de cette déclaration qui se trouvent dans le même fichier . (...).
- Apple, en Le langage de programmation Swift

33
Christophe

Python est également un langage qui adhère fortement à l'approche de programmation orientée objet. Il utilise l'approche classique des classes et des objets.

Cependant, la chose à retenir est que tout "mot" n'est qu'un contrat entre vous et les (futurs) mainteneurs. Avoir un nom différent, voire non explicite pour quelque chose ne signifie pas que ce contrat n'est pas là.

Python utilise le credo "nous sommes tous des adultes" et s'attend à ce que les gens travaillent avec les objets plutôt que contre. Ainsi, il considère tout ce qui est public et vous devez faire votre propre contrat en décrivant la classe. (PEP8, le livre de conception, remarque que le préfixe avec _ est une bonne idée de montrer le contrat des champs privés que les IDE comprennent).

Protégé (comme une idée que vous ne pouvez pas accéder directement à la variable, sauf si vous en dérivez) est de toute façon un contrat faible. Si vous souhaitez "prévenir" les erreurs dues à des modifications erronées de champs importants, pour protéger l'état interne, une variable protégée peut toujours changer à volonté, et une classe dérivée peut facilement l'exposer et la modifier mal.

La question devrait donc être posée à vous: "pourquoi ajouter un paradigme supplémentaire" à une langue sans utilisations avantageuses directes? YAGNI peut également postuler ici.

9
paul23

Avant de décider que le modificateur d'accès protégé doit être supprimé de toutes les langues populaires OO je voudrais souligner qu'il serait assez gênant de le perdre.

Dans les classes de base abstraites qui servent de modèle pour un certain nombre de classes dérivées, vous aurez probablement beaucoup de méthodes de support pour ces dérivés qui n'auront aucun sens pour l'utilisateur final de ces dérivés. Ergo, vous obtiendrez des interfaces bruyantes et vous devrez trouver un autre moyen de signaler que ces méthodes ne sont pas censées être appelées par les clients objets.

Certains diront qu'il existe des moyens de contourner cela. Que vous pouvez appliquer la composition à la place. Ils vous donneront un certain nombre de raisons de ne pas utiliser l'héritage en premier lieu. Quel que soit le mérite de ces déclarations, protégé est là pour soutenir l'application de l'héritage. Écrire des classes abstraites utiles sans protection va être difficile.

Je peux dire que je ne l'utilise pas beaucoup en dehors des classes de base abstraites. Mais tant que nous avons des classes de base abstraites, je voudrais garder mon mot-clé protégé merci.

8
Martin Maat

L'un des premiers langages orientés objet, Smalltalk, n'a pas de mot-clé ou de mécanisme protected, et private n'est pas non plus explicite mais implicite pour les variables d'instance, et suggéré par convention pour les méthodes. Fonctionne assez bien à moins que les gens ne voient la malléabilité comme une invitation à tout frapper avec un gros marteau :-)

3
Hans-Martin Mosner

protected concerne le contrôle d'accès aux données. OOP concerne l'encapsulation.

L'objectif principal de OOP est de structurer le code de telle sorte que les entités (données + opérations sur celui-ci) sont faiblement couplées les unes aux autres. Le fait que les données encapsulées soient contrôlées (relativement à leur accès) ou n'est pas une préoccupation nécessaire. La protection est plus étroitement liée à l'héritage; l'une des techniques pour réaliser la relation de généralisation/spécialisation. Mais même l'héritage n'est pas nécessaire, la délégation pourrait être utilisée pour mettre en œuvre beaucoup plus subtilement le G/S, et dans ce cas protégé n'est d'aucune utilité.

1

Comme l'a écrit Flater, les restrictions d'accès ne sont pas strictement nécessaires.

Et certains soutiennent que l'accès protégé tente de faire plusieurs choses à la fois. Vous pouvez utiliser protégé dans des cas comme:

  1. La méthode doit être appelée par des méthodes de sous-classe
  2. La méthode doit être implémentée par des méthodes de sous-classe et sera appelée par une super-classe ou d'autres sous-classes
  3. Méthode qui peut être remplacée par une sous-classe et sera appelée par une super-classe ou d'autres sous-classes
  4. des choses similaires avec Fields

meilleurs modificateurs (dans Java syntaxe ish):

  1. finale protégée
  2. divisé en deux méthodes, une protégée (ou privée, si les sous-classes ne sont pas censées l'appeler) finale (qui appelle) et une autre abstraite protégée que les sous-classes devraient implémenter, mais pas appeler.
  3. comme 2. mais sans résumé

Et pour le rendre plus court et plus clair, utilisez 3 mots différents.

0
user470365

Vous avez mentionné explicitement Swift, donc je vais vous expliquer pourquoi Swift n'a pas protected).

Contrairement à de nombreux autres langages, Swift vous permet d'écrire des "extensions" sur d'autres types (classes, structures, énumérations et protocoles), même ceux que vous ne possédez pas. De telles extensions peuvent même vous permettre pour rendre le type de la bibliothèque A conforme au protocole de la bibliothèque B (un exemple de "modélisation rétroactive"). Par exemple, vous pouvez avoir un objet Image (de la bibliothèque A) que vous souhaitez conformer au protocole de votre ORM DatabaseSerializable (de la bibliothèque B) afin qu'il puisse être sérialisé dans une base de données. Dans la plupart des langues, ce qui nécessite de tout emballer adaptateurs partout. Dans Swift, vous étendez simplement le Image directement pour se conformer à DatabaseSerializable

extension Image: DatabaseSerializable {
    func serailize(to db: Database) {
        // do whatever is necessary to save to the db or whatever
    }

C'est une fonctionnalité très centrale qui influence fortement le style de programmation fait dans Swift. Par exemple, ils sont fréquemment utilisés pour séparer visuellement les conformités à plusieurs protocoles, par exemple:

class Person {
    let firstName: String
    let lastName: String

    init(firstName: String, lastName: String) {
         self.firstName = firstName
         self.firstName = lastName
    }
}

// This impl can be auto-synthesized by the compiler, but I'm showing it here as an example anyway
extension Person: Equatable {
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.firstName == rhs.firstName && lhs.lastName == rhs.lastName
    }
}

// This impl can be auto-synthesized by the compiler, but I'm showing it here as an example anyway
extension Person: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(self.firstName)
        hasher.combine(self.lastName)
    }
}

extension Person: CustomStringConvertible {
    var description: String { "\(firstName) \(lastName)" }
}

Maintenant, dans cet exemple, imaginez qu'il y avait un champ protégé, socialInsuranceNumber. Si je suis dans le contexte d'une autre classe, elle ne devrait pas être accessible. Si je suis dans la classe Person ou une sous-classe, elle devrait être accessible. Mais que se passe-t-il si je suis dans le contexte d'une extension Person? Doit-elle dépendre du lieu de l'extension? (par exemple, autorisez-le dans le même module que Person, mais interdisez l'accès depuis l'extension dans d'autres modules). Que se passe-t-il si je fais cela?

extension Person {
    public var publicSocialInsuranceNumber: SIN {
        self.socialInsuranceNumber // this should be protected!
    }
}

Je viens de contourner trivialement les protections qu'offrirait un niveau d'accès protected.

Au lieu de cela, Swift a fileprivate, qui agit comme private, sauf que le champ est accessible à partir du fichier de définition. Donc, l'extension à Person dans Person.Swift peut accéder à socialInsuranceNumber, mais les extensions Person définies ailleurs ne le peuvent pas.

Dans Swift, il a été décidé qu'une sous-classe n'est pas significativement liée à la classe de base. Si certaines informations ne sont pas accessibles au public, elles ne devraient pas l'être pour une sous-classe.

Il existe également "fileprivate" qui permet aux membres d'être disponibles uniquement dans un fichier, donc si les classes sont fortement liées, elles peuvent être implémentées dans un seul fichier.

0
gnasher729