it-swarm.com.de

Ist in OOP das Schlüsselwort "protected" nicht erforderlich?

Einige moderne Sprachen (z. B. Swift, Dart) unterstützen das Schlüsselwort protected access modifier nicht. Swift ist eine protokollorientierte Sprache, aber ich habe gehört, dass Dart eine vollständig objektorientierte Sprache ist.

Warum unterstützen diese modernen Sprachen protected nicht? Benötigen Sie nur private und public für eine vollständige objektorientierte Programmierung?

Ich denke, es ist praktisch, ein Schlüsselwort für den Zugriffsmodifikator protected zu haben, wenn es Daten oder Schnittstellen gibt, die ich von der übergeordneten Klasse an die untergeordnete Klasse übergeben möchte. Warum unterstützen einige moderne Sprachen protected nicht?

28
ShutUpILoveYou

Es hängt davon ab, was Sie unter "erforderlich" verstehen.

Zugriffsmodifikatoren sind keine Notwendigkeit. Sie können jeden Zugriffsmodifikator durch public ersetzen, und die meisten Anwendungen funktionieren genauso wie bei Verwendung verschiedener Zugriffsmodifikatoren. Dies zeigt, dass das Hauptziel des Compilers (Ausgabe einer funktionierenden Anwendung) nicht direkt von Zugriffsmodifikatoren abhängt .

Wie Delioth in den Kommentaren erwähnt hat, sind sowohl Javascript als auch Python in der Lage OOP haben noch kein Konzept für Zugriffsmodifikatoren; beweisen den Punkt, dass = OOP erfordert keine Zugriffsmodifikatoren.

Zugriffsmodifikatoren sind jedoch aus Entwicklersicht sehr wichtig, wenn Sie Fehler vermeiden möchten. Das Fehlen von Zugriffsbeschränkungen führt dazu, dass Entwickler direkt auf Abhängigkeiten zugreifen, die sie nicht sollten (z. B. Umgehen einer Validierungs-/Autorisierungsschicht), und dies führt zu Fehlern, was zu Zeit- und Arbeitsaufwand führt.

Zusammenfassend lässt sich sagen, dass für den Compiler keine Zugriffsmodifikatoren erforderlich sind, diese werden jedoch meistens als sehr hilfreich für bewährte Verfahren angesehen. Solche Richtlinien "verlangen" von Entwicklern eine sorgfältige Zugriffskontrolle - auch wenn der Compiler diese nicht benötigt.

Warum entfernen einige moderne Sprachen das protected?

Es gibt keine allgemein gültige Antwort auf diese Frage, außer "weil die Sprachdesigner beschlossen haben, dies zu tun".

45
Flater

Nein, es ist nicht erforderlich: Bjarne Stroustrup, erklärt wie er naiv protected zu C++ Release 1.2 hinzugefügt hat, Denken Sie daran, Klassenentwicklern eine nützliche Funktion zur Verfügung zu stellen, um nur 5 Jahre später zu dem Schluss zu kommen, dass es sich um eine böse Fehlerquelle handelt, die glücklicherweise niemand verwenden musste. Heutzutage empfiehlt, es nicht zu verwenden .

Die praktischen Argumente gegen protected sind die Vorteile einer stärkeren Einkapselung und das Prinzip des geringsten Wissens :

  • Entweder ist ein Mitglied public und kann von jedem verwendet werden;
  • Oder das Mitglied ist private und muss vor externem Zugriff geschützt werden.
  • Ein protected -Mitglied, das eine sorgfältige Verwendung erfordert (andernfalls wäre es öffentlich), kann von Insidern (Entwicklern abgeleiteter Klassen) genauso missbraucht werden wie von anderen.

Formale Argumente bestätigen die praktische Erfahrung. Dies hat mit dem Liskov-Substitutionsprinzip und genauer mit seiner Geschichtsregel zu tun:

Wir sind der Meinung, dass es ausreichen sollte, wenn ein Benutzer nur den „scheinbaren“ Typ des Objekts kennt. Der Subtyp sollte alle Eigenschaften beibehalten, die über den Supertyp bewiesen werden können.
- Barbara Liskov & Jeanette Wing in Ein Verhaltensbegriff der Subtypisierung

Ohne auf die Details des zitierten Artikels einzugehen, erlauben die geschützten Mitglieder einer abgeleiteten Klasse (Subtyp), den Status des Basisklassenobjekts (Supertyp) auf unerwartete Weise zu ändern, ohne sich auf seine öffentlichen Operationen zu verlassen.

Vorsicht vor den Erscheinungen und falschen Versprechungen. Das Swift private liegt in anderen Sprachen zwischen private und protected:

Der private Zugriff beschränkt die Verwendung einer Entität auf die einschließende Deklaration und auf Erweiterungen dieser Deklaration, die sich in derselben Datei befinden . (...).
- Apple, in Die Swift Programmiersprache

33
Christophe

Python ist auch eine Sprache, die sich stark an den objektorientierten Programmieransatz hält. Es verwendet den klassischen Ansatz von Klassen und Objekten.

Beachten Sie jedoch, dass jedes "Wort" nur ein Vertrag zwischen Ihnen und (zukünftigen) Betreuern ist. Ein anderer oder sogar nicht expliziter Name für etwas bedeutet nicht, dass dieser Vertrag nicht vorhanden ist.

Python verwendet das Credo "Wir sind alle Erwachsene" und erwartet, dass die Leute mit den Objekten arbeiten, anstatt dagegen. Daher wird alles öffentlich betrachtet, und Sie müssen Ihren eigenen Vertrag abschließen, indem Sie die Klasse beschreiben. (PEP8, das Designbuch, bemerkt, dass das Präfix _ ist eine gute Idee, um den Vertrag von privaten Feldern zu zeigen (IDEs verstehen dies).

Geschützt (als Idee, dass Sie nicht direkt auf die Variable zugreifen können, außer wenn Sie davon abgeleitet sind) ist sowieso ein schwacher Vertrag. Wenn Sie Fehler aufgrund fehlerhafter Änderungen an wichtigen Feldern "verhindern" möchten, um den internen Status zu schützen, kann sich eine geschützte Variable nach Belieben ändern, und eine abgeleitete Klasse kann dies leicht verfügbar machen und schlecht ändern.

Die Frage sollte also bei Ihnen liegen: "Warum ein zusätzliches Paradigma hinzufügen" zu einer Sprache ohne direkte vorteilhafte Verwendung? YAGNI könnte auch hier gelten.

9
paul23

Bevor wir entscheiden, dass der Modifikator für den geschützten Zugriff aus allen gängigen OO Sprachen) entfernt werden muss, möchte ich darauf hinweisen, dass es ziemlich unpraktisch wäre, ihn zu verlieren.

In abstrakten Basisklassen, die als Vorlage für eine Reihe abgeleiteter Klassen dienen, stehen Ihnen wahrscheinlich viele Unterstützungsmethoden für diese Derivate zur Verfügung, die für den Endbenutzer dieser Derivate bedeutungslos sind. Ergo erhalten Sie verrauschte Schnittstellen und müssen einen anderen Weg finden, um zu signalisieren, dass diese Methoden nicht von Objektclients aufgerufen werden sollen.

Einige mögen sagen, dass es Wege gibt, das zu umgehen. Dass Sie stattdessen Komposition anwenden können. Sie geben Ihnen eine Reihe von Gründen, die Vererbung überhaupt nicht zu verwenden. Welchen Wert diese Aussagen auch haben mögen, geschützt dient die Anwendung der Vererbung. Das Schreiben nützlicher abstrakter Klassen ohne Schutz wird schwierig.

Ich kann sagen, dass ich es außerhalb abstrakter Basisklassen nicht oft benutze. Aber solange wir abstrakte Basisklassen haben, möchte ich mein geschütztes Schlüsselwort behalten, danke.

8
Martin Maat

Eine der ersten objektorientierten Sprachen, Smalltalk, hat kein Schlüsselwort oder keinen Mechanismus protected, und private ist ebenfalls nicht explizit, sondern impliziert beispielsweise Instanzvariablen und wird durch Konventionen für Methoden vorgeschlagen. Funktioniert ziemlich gut, es sei denn, die Leute sehen die Formbarkeit als Einladung, alles mit einem großen Hammer zu schlagen :-)

3

Bei protected geht es um die Zugriffskontrolle von Daten. OOP handelt von der Kapselung.

Das Hauptziel von OOP ist es, den Code so zu strukturieren, dass Entitäten (Daten + Operationen darauf) schwach miteinander gekoppelt sind. Die Tatsache, dass gekapselte Daten gesteuert werden (relativ zu ihrem Zugriff) oder Nicht ist kein notwendiges Anliegen. Schutz ist enger mit Vererbung verbunden, eine der Techniken zur Realisierung der Generalisierungs-/Spezialisierungsbeziehung. Aber selbst Vererbung ist nicht notwendig, Delegation könnte verwendet werden, um das G/S viel subtiler zu implementieren, und in Dieser geschützte Fall nützt nichts.

Wie Flater schrieb, sind Zugangsbeschränkungen nicht unbedingt erforderlich.

Und einige argumentieren, dass geschützter Zugriff versucht, mehrere Dinge gleichzeitig zu tun. Sie können protected in folgenden Fällen verwenden:

  1. Die Methode sollte von Unterklassenmethoden aufgerufen werden
  2. Die Methode sollte durch Unterklassenmethoden implementiert werden und wird von Oberklassen oder anderen Unterklassen aufgerufen
  3. Methode, die von Unterklassen überlagert werden kann und von Oberklassen oder anderen Unterklassen aufgerufen wird
  4. ähnliche Dinge mit Feldern

bessere Modifikatoren (in Java ish Syntax):

  1. geschütztes Finale
  2. aufgeteilt in zwei Methoden, eine geschützte (oder private, wenn Unterklassen sie nicht aufrufen sollen) final (die aufruft) und eine andere geschützte Zusammenfassung, die Unterklassen implementieren, aber nicht aufrufen sollten.
  3. wie 2. aber ohne abstrakt

Und um es kürzer und klarer zu machen, verwenden Sie 3 verschiedene Wörter.

0
user470365

Sie haben Swift explizit erwähnt, also werde ich antworten, warum Swift hat kein protected).

Im Gegensatz zu vielen anderen Sprachen können Sie mit Swift "Erweiterungen" für andere Typen (Klassen, Strukturen, Aufzählungen und Protokolle) schreiben, auch für solche, die Sie nicht besitzen. Mit solchen Erweiterungen können Sie sogar Um den Typ von Bibliothek A an das Protokoll von Bibliothek B anzupassen (ein Beispiel für "rückwirkende Modellierung"). Möglicherweise haben Sie ein Objekt Image (aus Bibliothek A), das Sie an das Protokoll Ihres ORM anpassen möchten DatabaseSerializable (aus Bibliothek B), damit es in eine Datenbank serialisiert werden kann. In den meisten Sprachen, in denen alles zusammengefasst werden muss Adapter überall. In Swift erweitern Sie einfach die Image direkt zur Anpassung an DatabaseSerializable

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

Sie sind ein sehr zentrales Merkmal, das den Programmierstil von Swift stark beeinflusst. Beispielsweise werden sie häufig verwendet, um Konformitäten visuell von mehreren Protokollen zu trennen, zum Beispiel:

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)" }
}

Stellen Sie sich in diesem Beispiel vor, es gäbe ein geschütztes Feld, socialInsuranceNumber. Wenn ich im Kontext einer anderen Klasse bin, sollte sie nicht zugänglich sein. Wenn ich in der Klasse Person oder einer Unterklasse bin, sollte darauf zugegriffen werden können. Aber was passiert, wenn ich mich im Kontext einer Person -Erweiterung befinde? Sollte es davon abhängen, wo die Erweiterung durchgeführt wird? (z. B. im selben Modul wie Person zulassen, aber den Zugriff von der Erweiterung in anderen Modulen nicht zulassen). Was passiert, wenn ich das mache?

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

Ich habe den Schutz, den eine protected Zugriffsebene bieten würde, nur trivial umgangen.

Stattdessen hat Swift hat fileprivate, was sich wie private verhält, außer dass auf das Feld über die definierende Datei zugegriffen werden kann. Erweitern Sie also auf PersonPerson.Swift kann auf socialInsuranceNumber zugreifen, Person -Erweiterungen, die an anderer Stelle definiert sind, jedoch nicht.

In Swift wurde entschieden, dass eine Unterklasse nicht wesentlich mit der Basisklasse zusammenhängt. Wenn einige Informationen der Öffentlichkeit nicht zugänglich sind, sollten sie einer Unterklasse nicht zur Verfügung stehen.

Es gibt auch "fileprivate", mit dem Mitglieder nur innerhalb einer Datei verfügbar sein können. Wenn also Klassen stark miteinander verwandt sind, können sie in einer Datei implementiert werden.

0
gnasher729