Private vs. öffentliche Mitglieder in der Praxis (wie wichtig ist Kapselung?) [Geschlossen]

StackOverflow https://stackoverflow.com/questions/99688

  •  01-07-2019
  •  | 
  •  

Frage

Einer der größten Vorteile der objektorientierten Programmierung ist Verkapselung und einer der „Wahrheiten“ wir haben (oder zumindest habe ich) unterrichtet worden ist, dass die Mitglieder sollten immer privat gemacht werden und zur Verfügung über Accessor und Mutator-Methoden, also die Fähigkeit, sicherzustellen, um die Änderungen zu überprüfen und zu bestätigen.

Ich bin gespannt, obwohl, wie wichtig dies in der Praxis wirklich ist. Insbesondere haben, wenn Sie ein komplizierteres Element (wie zum Beispiel einer Sammlung) bekommen, kann es sehr verlockend sein, nur eher es öffentlich machen als eine Reihe von Methoden machen die Sammlung der Schlüssel, Hinzufügen / Entfernen von Artikeln aus der Sammlung, etc.

Haben Sie die Regel in der Regel folgen? Ist Ihre Antwort ändern, je nachdem ob es für sich selbst Code geschrieben gegen die von anderen verwendet werden? Gibt es subtilere Gründe fehlt mir für diese Verschleierung?

War es hilfreich?

Lösung

Es hängt davon ab. Dies ist eines der Themen, die pragmatisch entschieden werden muss.

Angenommen, ich eine Klasse hatte einen Punkt für die Darstellung. Ich konnte Getter und Setter für die X und Y-Koordinaten, oder ich konnte sie nur beide öffentlich machen und frei Lese- / Schreibzugriff auf die Daten ermöglichen. Meiner Meinung nach ist dies in Ordnung, weil die Klasse wie eine verherrlichte Struktur handeln -. Eine Datensammlung mit vielleicht einigen nützlichen Funktionen angebracht

Allerdings gibt es viele Situationen, in denen Sie nicht wollen, vollen Zugriff auf Ihre internen Daten zur Verfügung zu stellen und stützen sich auf den Methoden, die von der Klasse, die mit dem Objekt zu interagieren. Ein Beispiel wäre eine HTTP-Anfrage und Antwort sein. In diesem Fall ist es eine schlechte Idee, jemand zu erlauben, etwas über den Draht zu schicken - es muss verarbeitet und durch die Klassenmethoden formatiert werden. In diesem Fall wird die Klasse der als eigentliches Objekt konzipiert und nicht einem einfachen Datenspeicher.

Es kommt wirklich darauf an, ob die Verben (Methoden), um die Struktur fahren oder wenn die Daten der Fall ist.

Andere Tipps

Als jemand mehr Jahre alten Code zu erhalten, die von vielen Menschen in der Vergangenheit gearbeitet, es mir sehr klar, dass, wenn ein Mitglied Attribut öffentlich gemacht wird, wird sie schließlich missbraucht. Ich habe sogar Leute nicht einverstanden mit der Idee von Zugriffs- und Mutatoren gehört, wie das ist immer noch nicht wirklich auf den Zweck der Verkapselung lebender auf, welches „das Innenleben einer Klasse zu verstecken“. Es ist natürlich ein umstrittenes Thema, aber meine Meinung nach würde „machen wird jedes Mitglied Variable privat, denkt in erster Linie über das, was die Klasse hat bekommt tun (Methoden) anstatt wie Sie‘ re Menschen gehen interne Variablen ändern lassen“.

Ja, Verkapselung Angelegenheiten. Aussetzen der zugrunde liegende Implementierung hat (mindestens) zwei Dinge falsch:

  1. mischt Verantwortlichkeiten. Anrufer sollten nicht die zugrunde liegende Implementierung verstehen müssen oder wollen. Sie sollten nur die Klasse wollen ihre Arbeit zu tun. Durch die zugrunde liegende Implementierung aussetzt, du bist Klasse ist seine Arbeit nicht tun. Stattdessen ist es nur die Verantwortung auf den Anrufer drückt.
  2. Ties Sie auf die zugrunde liegende Implementierung. Sobald Sie die zugrunde liegende Implementierung aussetzen, sind Sie an sie gebunden. Wenn Sie Anrufer sagen, zum Beispiel, gibt es eine Sammlung unter, können Sie nicht einfach die Sammlung für eine neue Implementierung tauschen.

Diese (und andere) Probleme gelten unabhängig davon, ob Sie einen direkten Zugriff auf die zugrunde liegende Implementierung geben oder einfach duplizieren alle zugrunde liegenden Methoden. Sie sollten die notwendige Umsetzung aussetzen, und nichts mehr. die Umsetzung private Haltung macht das Gesamtsystem besser verwaltbar.

Ich ziehe Mitglieder privat so lange wie möglich und nur Zugang em über Getter zu halten, auch innerhalb der gleichen Klasse. Ich versuche auch Setter als ein erster Entwurf zu vermeiden wert Objekte zu fördern, solange es möglich ist. mit Dependency Injection arbeiten, haben viel Sie oft Setter, aber keine Getter, wie Kunden sollten das Objekt konfigurieren können, aber (andere) nicht erhalten wissen, was acutally wie dieses Detail eine Implementierung konfiguriert ist, ist.

Viele Grüße, Ollie

Ich neige dazu, die Regel ziemlich streng zu folgen, auch wenn es nur mein eigener Code. Ich mag Eigenschaften in C # aus diesem Grund. Es macht es wirklich einfach zu steuern, was es gegeben Werte, aber Sie können immer noch sie als Variablen verwenden. Oder die eingestellte privat machen und die Öffentlichkeit erhalten, etc.

Grundsätzlich Information Hiding ist über Code Klarheit. Es wurde entwickelt, es einfacher für jemanden zu machen, sonst Ihren Code zu erweitern, und zu verhindern, dass sie versehentlich Bugs zu schaffen, wenn sie mit den internen Daten Ihrer Klassen arbeiten. Es basiert auf dem Prinzip, dass niemand liest Kommentare , insbesondere solche mit Anweisungen in ihnen.

Beispiel: Ich bin das Schreiben von Code, der eine Variable aktualisiert, und ich brauche unbedingt darauf zu achten, dass die Gui Änderungen die Änderung widerzuspiegeln, ist der einfachste Weg, um eine Accessor-Methode hinzuzufügen (auch bekannt als ein „Setter“), die anstelle der Aktualisierung von Daten aufgerufen wird, aktualisiert wird.

Wenn ich machen, dass die Daten der Öffentlichkeit, und sich etwas ändert die Variable ohne die Setter-Methode geht (und das passiert jeden schwören-Wort-Zeit), dann wird jemand brauchen eine Stunde Debuggen verbringen, um herauszufinden, warum die Updates nicht sind wird angezeigt. Das gleiche gilt in geringerem Maße auf „Getting“ Daten. Ich kann einen Kommentar in der Header-Datei setzen, aber Chancen sind, dass niemand wird es lesen, bis etwas schrecklich geht, schrecklich falsch. Erzwingen es mit privaten Mitteln, dass der Fehler nicht gemacht werden, da es sich als ein leicht auffindbar Kompilierung-Fehler zeigen werde, anstatt eine Laufzeit Fehler.

Aus der Erfahrung, die nur mal würden Sie wollen eine Membervariable öffentlich machen, und auszulassen Getter und Setter-Methoden, ist, wenn Sie es absolut klar, dass eine Änderung machen wollen wird es keine Nebenwirkungen haben; vor allem, wenn die Datenstruktur ist einfach, wie eine Klasse, die einfach zwei Variablen als Paar hält.

Dies sollte ein ziemlich seltenes Vorkommen sein, wie es normalerweise würden Sie wollen Nebenwirkungen, und wenn die Datenstruktur Sie erstellen so einfach ist, dass Sie dies nicht tun (zB eine Paarung), es wird bereits ein effizienter ein in einer Standardbibliothek geschrieben.

Mit dieser sagte, für die meisten kleinen Programme, die ein verwenden keine Verlängerung, wie die, die Sie an der Universität bekommen, ist es mehr „gute Praxis“ als alles andere, weil Sie über den Verlauf sie zu schreiben erinnern werden, und dann werden Sie sie in die Hand und nie wieder den Code berühren. Auch, wenn Sie sind eine Datenstruktur als eine Möglichkeit, das Schreiben, herauszufinden, wie sie Daten speichern und nicht als Freigabe-Code, dann ist es ein gutes Argument, dass Getter und Setter werden nicht helfen, und werden in der Art und Weise der Lernerfahrung bekommen .

Es ist nur, wenn Sie an dem Arbeitsplatz oder ein großes Projekt zu bekommen, wo die Wahrscheinlichkeit Ihr Code von verschiedenen Personen geschrieben von Objekten und Strukturen genannt wird, ist, dass es von entscheidenden Bedeutung wird diese „Erinnerungen“ stark zu machen. Unabhängig davon, ob es ist ein einziges Mann-Projekt überraschend irrelevant ist, aus dem einfachen Grunde, dass „Sie 6 Wochen ab jetzt“ sind auch als anderer Mensch als Mitarbeiter. Und „mir vor sechs Wochen“ oft stellt sich heraus, faul zu sein.

Ein letzter Punkt ist, dass einige Leute über Information Hiding ziemlich eifrig sind, und verärgert, wenn Ihre Daten unnötig öffentlich ist. Es ist am besten zum Humor sie.

C # Eigenschaften 'Simulieren' öffentlichen Bereichen. Sieht ziemlich cool und die Syntax beschleunigt wirklich diejenigen get / set-Methoden zu schaffen

Beachten Sie die Semantik der Methoden auf einem Objekt aufgerufen wird. Ein Methodenaufruf ist eine sehr hohe Abstraktion, die meinen, den Compiler implementiert werden können, oder das Laufzeitsystem in einer Vielzahl von verschiedenen Möglichkeiten.

Wenn das Objekt, die die Methode Sie sich berufen in der gleichen Prozess / Speicherkarte existiert dann ein Verfahren auch durch einen Compiler oder VM optimiert werden kann, um direkt die Daten Mitglied zugreifen. Auf der anderen Seite, wenn das Objekt lebt auf einem anderen Knoten in einem verteilten System, dann gibt es keine Möglichkeit, dass Sie direkt es Mitglieder interne Daten zugreifen können, aber man kann immer noch seine Methoden meines rufen Sie ihm eine Nachricht zu senden.

Mit dem Sie Code schreiben können Schnittstellen Codierung, die nicht egal ist, wo das Zielobjekt vorhanden ist oder wie es Methoden aufgerufen werden oder auch wenn es in der gleichen Sprache geschrieben ist.


In Ihrem Beispiel eines Objekts, das alle Methoden einer Sammlung implementiert, dann sicher das Objekt tatsächlich ist eine Sammlung. so vielleicht wäre dies ein Fall sein, wenn Vererbung besser als Kapselung wäre.

Es geht darum, zu steuern, was die Menschen mit tun können, was Sie ihnen geben. Je mehr Kontrolle Sie sind die mehr Annahmen Sie machen können.

Auch theorectically können Sie die zugrunde liegende Implementierung oder etwas ändern, aber da in den meisten Fällen ist es:

private Foo foo;
public Foo getFoo() {}
public void setFoo(Foo foo) {}

Es ist ein wenig schwer zu rechtfertigen.

Die Einkapselung ist wichtig, wenn zumindest eine davon hält:

  1. Wer aber sie wird Ihre Klasse verwenden (oder sie werden Ihre Invarianten brechen, weil sie in der Dokumentation nicht lesen).
  2. Wer nicht in der Dokumentation liest wird Ihre Klasse verwenden (oder sie werden Ihre sorgfältig dokumentiert Invarianten brechen). Beachten Sie, dass diese Kategorie gehören Sie-zwei-Jahre-von-jetzt.
  3. An einem gewissen Punkt in der Zukunft jemand geht von Ihrer Klasse erben (weil vielleicht eine zusätzliche Maßnahmen ergriffen werden muss, wenn der Wert eines Feldes ändert, so dass es ein Setter sein).

Wenn es nur für mich, und in wenigen Orten verwendet wird, und ich werde nicht von ihm erben, und Ändern von Feldern werden ungültig macht keine Invarianten, die die Klasse geht davon aus, dann nur I behält sich das Recht ein Feld öffentlich machen.

Meine Tendenz ist zu versuchen, alles privat, wenn möglich zu machen. Dies hält Objektgrenzen so klar wie möglich definiert und hält die Objekte so weit wie möglich entkoppelt. Ich mag das, weil, wenn ich ein Objekt neu zu schreiben, dass ich die erste (zweite, fünfte?) Verpfuschte Zeit, den Schaden auf eine kleinere Anzahl von Objekten enthalten hält.

Wenn Sie koppeln die Objekte fest genug, es einfacher sein kann nur kombinieren sie zu einem Objekt zusammen. Wenn Sie die Kopplung Einschränkungen genug entspannen sind Sie wieder auf strukturierte Programmierung.

Es kann sein, dass, wenn Sie feststellen, dass ein Haufen Ihre Objekte sind Accessorfunktionen nur, sollten Sie Ihr Objekt Divisionen überdenken. Wenn Sie keine Aktionen auf diesen Daten tun es kann als ein Teil eines anderen Objekts gehören.

Natürlich, wenn Sie ein etwas wie eine Bibliothek schreiben wollen Sie so klar und scharf eine Schnittstelle wie möglich, so dass andere dagegen programmieren können.

Das Werkzeug für den Job ... vor kurzem habe ich einige Codes wie dies in meiner aktuellen Code-Basis:

private static class SomeSmallDataStructure {
    public int someField;
    public String someOtherField;
}

Und dann wurde diese Klasse intern für leicht, das um mehrere Datenwerte verwendet. Es ist nicht immer sinnvoll, aber wenn Sie nur Daten haben, ohne Methoden, und Sie sind aussetzt es nicht Kunden, finde ich es ziemlich nützlich Muster.

Die jüngste Anwendung ich davon hatte, war eine JSP-Seite, wo ich eine Tabelle von Daten genommen wurde deklarativ im oberen Bereich angezeigt, definiert. Also, zunächst in mehreren Arrays war, ein Array pro Datenfeld ... endete dies in der Code ist ziemlich schwierig zu durchwaten mit Feldern nicht nebeneinander in der Bedeutung sein, die zusammen angezeigt werden würden ... so habe ich eine einfache Klasse wie oben die sie zusammen ziehen würde ... das Ergebnis war wirklich lesbarer Code, viel mehr als zuvor.

Moral ... manchmal sollte man bedenkt, „akzeptiert schlecht“ Alternativen, wenn sie den Code einfacher und leichter machen kann, so lange zu lesen, wie man es zu Ende denkt und die Folgen betrachten ... nehmen nicht blind alles was Sie hören .

Das sagte ... public Getter und Setter ist so ziemlich gleichwertig zu öffentlichen Bereichen ... zumindest im Wesentlichen (es ein bisschen mehr Flexibilität, aber es ist immer noch ein schlechtes Muster auf jedes Feld müssen Sie gelten).

Auch die Java-Standardbibliotheken hat einige Fälle von

Wenn ich machen Objekte sinnvoll sie sind leichter und leichter zu halten .

Zum Beispiel: Person.Hand.Grab (howquick, howmuch);

Der Trick ist nicht zu denken, von Mitgliedern als einfache Werte, sondern Gegenstände an sich selbst.

Ich würde behaupten, dass diese Frage tut mix-up, das Konzept der Kapselung mit ‚Information Hiding‘
(Dies ist kein Kritiker, da es eine gemeinsame Auslegung des Begriffs der ‚Kapselung‘ zu passen scheint)

Doch für mich, 'Kapselung' entweder:

  • der Prozess mehrere Gegenstände in einen Behälter mit Umgruppierung
  • der Behälter selbst die Elemente Umgruppierung

Angenommen, Sie ein Steuerzahler System entwerfen. Für jeden Steuerzahler, könnten Sie encapsulate der Begriff der Kind in

  • eine Liste von Kindern, die die Kinder
  • eine Karte zu berücksichtigt Kinder aus verschiedenen Eltern
  • ein Objekt Kinder (nicht Kind), die die benötigten Informationen (wie Gesamtzahl der Kinder) bieten würde

Hier haben Sie drei verschiedene Arten von Verkapselungen, 2, dargestellt durch Low-Level-Container (Liste oder Karte), einer durch ein Objekt dargestellt.

Mit diesen Entscheidungen, die Sie nicht

  • , dass die Verkapselung öffentlich machen oder geschützt oder privat: die Wahl von ‚Information Hiding‘ noch gemacht werden soll
  • machen eine vollständige Abstraktion (die Attribute des Objekts Kinder einschränken müssen und Sie können entscheiden, ein Objekt Kind zu schaffen, die nur die relevanten Informationen aus der Sicht eines Steuerzahler System halten würde)
    Abstraktion ist der Prozess der Entscheidung, welche der Objektattribute sind relevant für Ihr System, und die völlig außer Acht gelassen werden dürfen.

Also mein Punkt ist:
Diese Frage kann worden betitelt:
Private vs. öffentliche Mitglieder in der Praxis (wie wichtig ist Information Hiding ?)

Just my 2 cents, though. Ich achte genau, dass eine Verkapselung als ein Verfahren, das ‚Information Hiding‘ betrachten kann Entscheidung.

Aber ich versuche immer, 'Abstraktion' zu unterscheiden - 'Kapselung' -. 'Information Hiding oder Sichtbarkeit'

Ich finde viele Getter und Setter ein Code zu riechen , dass die Struktur des Programm ist nicht gut gestaltet. Sie sollten den Code anschauen, die diese Getter und Setter, und suchen Sie nach Funktionalität verwendet, die wirklich sollte ein Teil der Klasse sein. In den meisten Fällen sollen die Felder einer Klasse private Implementierungsdetails werden und nur die Methoden dieser Klasse können sie manipulieren.

beide Getter und Setter zu haben, ist gleich dem Feld öffentlich sein (wenn die Getter und Setter sind trivial / automatisch generiert). Manchmal ist es besser, nur die Felder der Öffentlichkeit zu erklären, so dass der Code einfacher sein wird, es sei denn, Sie benötigen Polymorphismus oder ein Framework erfordert get / set-Methoden (und Sie können nicht den Rahmen ändern).

Es gibt aber auch Fälle, in denen mit Getter und Setter ein gutes Muster ist. Ein Beispiel:

Wenn ich die GUI von einer Anwendung zu erstellen, ich versuche, das Verhalten der GUI in einer Klasse (FooModel) zu halten, so dass es Einheit leicht geprüft werden kann, und habe die Visualisierung der GUI in einer anderen Klasse (FooView), das kann nur manuell getestet werden. Die Ansicht und Modell sind mit einfachen Glue-Code verbunden ist; wenn der Benutzer den Wert des Feldes x ändert, ruft der Ansicht setX(String) auf dem Modell, das wiederum ein Ereignis auslösen kann, dass ein anderer Teil des Modells hat sich verändert, und die Ansicht wird die aktualisierten Werte aus dem Modell mit Getter bekommen.

In einem Projekt gibt es ein GUI-Modell, das 15 Getter und Setter hat, von denen nur drei get-Methoden trivial sind (so dass die IDE können sie erzeugen). Alle anderen enthalten einige Funktionalität oder nicht-triviale Ausdrücke wie folgt:

public boolean isEmployeeStatusEnabled() {
    return pinCodeValidation.equals(PinCodeValidation.VALID);
}

public EmployeeStatus getEmployeeStatus() {
    Employee employee;
    if (isEmployeeStatusEnabled()
            && (employee = getSelectedEmployee()) != null) {
        return employee.getStatus();
    }
    return null;
}

public void setEmployeeStatus(EmployeeStatus status) {
    getSelectedEmployee().changeStatusTo(status, getPinCode());
    fireComponentStateChanged();
}

In der Praxis habe ich immer nur eine Regel folgen, die "no size fits all" -Regel.

Encapsulation und seine Bedeutung ist ein Produkt Ihres Projektes. Welche Aufgabe wird Ihre Schnittstelle zugreifen, wie sie es verwenden, wird es eine Rolle, wenn sie nicht benötigten Zugriffsrechte auf Mitglieder haben? diese Fragen und die gerne von ihnen Sie müssen sich fragen, wenn an jedem Projektumsetzung arbeiten.

Ich stütze meine Entscheidung über die Tiefe des Kodex innerhalb eines Moduls. Wenn ich writting Code, der zu einem Modul intern ist, und nicht eine Schnittstelle mit der Außenwelt ich kapseln die Dinge nicht mit eigenem so viel, weil es meine Programmierer Leistung auswirkt (wie schnell kann ich schreiben und meinen Code umschreiben).

Aber für die Objekte, die Server als die Schnittstelle des Moduls mit Benutzercode, dann halte ich mich an strenge Datenschutz Muster.

Sicher macht es einen Unterschied, ob die internen Code oder das Schreiben von Code von jemand anderem verwendet werden (oder sogar selbst, sondern als eine geschlossene Einheit.) Jeder Code, der verwendet werden wird extern eine gut definierte / dokumentiert haben sollte Schnittstelle, die Sie wollen, werden so wenig wie möglich zu verändern.

Für den internen Code, je nach Schwierigkeitsgrad, können Sie feststellen, es ist weniger Arbeit Dinge die einfache Art und Weise jetzt zu tun, und zahlen ein wenig später Strafe. Natürlich wird dafür sorgen, Murphys Gesetz, dass der kurzfristige Gewinn über viele Male gelöscht werden in mit weitreichenden Änderungen später zu machen, wo man benötigt, um eine Klasse Interna zu ändern, die Sie kapseln fehlgeschlagen.

Speziell zu Ihrem Beispiel eine Sammlung, die Sie zurückkehren würde, scheint es möglich, dass die Umsetzung einer solchen Sammlung ändern könnte (im Gegensatz zu einfacheren Membervariablen) höher die Nützlichkeit der Verkapselung zu machen.

aber sagen, dass ich ein bisschen wie Pythons Art und Weise des Umgangs mit ihr. Membervariablen sind standardmäßig öffentlich. Wenn Sie wollen, dass sie verstecken oder Validierung dort hinzuzufügen sind Techniken zur Verfügung gestellt, aber das ist die Sonderfälle berücksichtigt.

Ich folge den Regeln auf dieser fast die ganze Zeit. Es gibt vier Szenarien für mich - im Grunde die Regel selbst und mehrere Ausnahmen (alle Java-beeinflussbaren):

  1. Verwendbar von etwas außerhalb der aktuellen Klasse, zugegriffen über Getter / Setter
  2. Interne-to-Klasse Verwendung typischerweise mit vorangestelltem ‚dies‘, um klarzustellen, dass es keine Methode Parameter
  3. Etwas bedeutete extrem klein zu bleiben, wie ein Transportobjekt - im Grunde einen gerade Schuss von Attributen; alle öffentlichen
  4. Erforderlich für die Erweiterung von einer Art nicht privat sein

Es gibt eine praktische Anliegen hier, die nicht von den meisten der bestehenden Antworten angesprochen wird. Die Verkapselung und die Exposition von sauberen, sicheren Schnittstellen nach außen Code ist immer toll, aber es ist viel wichtiger, wenn der Code Sie schreiben verbraucht werden soll, durch eine spatially- und / oder zeitlich große „user“ Basis. Was ich meine ist, dass wenn man auf jemanden planen (auch Sie) den Code auch in Zukunft beibehalten wird, oder wenn Sie ein Modul zu schreiben, die mit dem Code von mehr als einer Handvoll anderer Entwickler-Schnittstelle werden Sie viel mehr zu denken brauchen sorgfältig, als wenn Sie Code schreiben, die von Ihnen entweder einmalig oder vollständig geschrieben ist.

Ehrlich gesagt, weiß ich, was elende Software-Engineering-Praxis ist dies, aber ich werde oft zunächst alles öffentlich machen, die Dinge geringfügig schneller zu erinnern und Art macht, dann Verkapselung hinzufügen, wie es Sinn macht. Refactoring-Tools in den meisten gängigen IDEs in diesen Tagen macht, die Sie verwenden Ansatz (Hinzufügen Kapselung gegen sie wegzunehmen) viel weniger relevant als früher sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top