Code wie:
public Thing[] getThings(){
return things;
}
Das macht nicht viel Sinn, da Ihre Zugriffsmethode nichts anderes tut, als die interne Datenstruktur direkt zurückzugeben. Sie können genauso gut erklären, Thing[] things
zu sein public
. Die Idee hinter einer Zugriffsmethode besteht darin, eine Schnittstelle zu erstellen, die Clients vor internen Änderungen schützt und sie daran hindert, die tatsächliche Datenstruktur zu manipulieren, außer auf diskrete Weise, wie es die Schnittstelle zulässt. Wie Sie festgestellt haben, als Ihr gesamter Client-Code fehlerhaft war, hat Ihre Zugriffsmethode dies nicht getan - es ist nur verschwendeter Code. Ich denke, viele Programmierer neigen dazu, solchen Code zu schreiben, weil sie irgendwo gelernt haben, dass alles mit Zugriffsmethoden gekapselt werden muss - aber das ist aus den Gründen, die ich erklärt habe. Es ist nur Rauschen, es nur zu tun, um der Form zu folgen, wenn die Zugriffsmethode keinen Zweck erfüllt.
Ich würde auf jeden Fall Ihre vorgeschlagene Lösung empfehlen, die einige der wichtigsten Ziele der Kapselung erreicht: Kunden eine robuste, diskrete Schnittstelle zu bieten, die sie von den internen Implementierungsdetails Ihrer Klasse isoliert und ihnen nicht erlaubt, die interne Datenstruktur zu berühren Erwarten Sie in der Art und Weise, wie Sie sich für angemessen halten - "das Gesetz der am wenigsten notwendigen Privilegien". Wenn Sie sich die großen, beliebten OOP-Frameworks wie CLR, STL und VCL ansehen, ist das von Ihnen vorgeschlagene Muster genau aus diesem Grund weit verbreitet.
Solltest du das immer tun? Nicht unbedingt. Wenn Sie beispielsweise Helfer- oder Freundklassen haben, die im Wesentlichen Bestandteil Ihrer Hauptarbeiterklasse sind und nicht "nach vorne gerichtet" sind, ist dies nicht erforderlich - es ist ein Overkill, der viel unnötigen Code hinzufügt. Und in diesem Fall würde ich überhaupt keine Zugriffsmethode verwenden - es ist sinnlos, wie erklärt. Deklarieren Sie die Datenstruktur einfach so, dass sie nur für die Hauptklasse gilt, die sie verwendet - die meisten Sprachen unterstützen dies - friend
oder deklarieren Sie sie in derselben Datei wie die Hauptarbeiterklasse usw.
Der einzige Nachteil, den ich in Ihrem Vorschlag sehen kann, ist, dass das Codieren mehr Arbeit ist (und jetzt müssen Sie Ihre Verbraucherklassen neu codieren - aber Sie haben / mussten das trotzdem tun.) Aber das ist nicht wirklich ein Nachteil - Sie müssen es richtig machen, und manchmal erfordert das mehr Arbeit.
Eines der Dinge, die einen guten Programmierer gut machen, ist, dass er weiß, wann sich die zusätzliche Arbeit lohnt und wann nicht. Auf lange Sicht wird sich das Einsetzen des Extra jetzt in Zukunft mit großen Dividenden auszahlen - wenn nicht bei diesem Projekt, dann bei anderen. Lernen Sie, richtig zu codieren und verwenden Sie Ihren Kopf, um nicht nur den vorgeschriebenen Formularen zu folgen.
Beachten Sie, dass für Sammlungen, die komplexer als Arrays sind, die einschließende Klasse möglicherweise sogar mehr als drei Methoden implementieren muss, um auf die interne Datenstruktur zuzugreifen.
Wenn Sie eine gesamte Datenstruktur über eine enthaltende Klasse verfügbar machen, müssen Sie IMO darüber nachdenken, warum diese Klasse überhaupt gekapselt ist, wenn nicht nur eine sicherere Schnittstelle bereitgestellt werden soll - eine "Wrapper-Klasse". Sie sagen, dass die enthaltende Klasse für diesen Zweck nicht existiert - vielleicht stimmt etwas an Ihrem Design nicht. Teilen Sie Ihre Klassen in diskretere Module auf und überlagern Sie sie.
Eine Klasse sollte einen klaren und diskreten Zweck haben und eine Schnittstelle zur Unterstützung dieser Funktionalität bereitstellen - nicht mehr. Möglicherweise versuchen Sie, Dinge zu bündeln, die nicht zusammen gehören. Wenn Sie dies tun, werden die Dinge jedes Mal kaputt gehen, wenn Sie eine Änderung implementieren müssen. Je kleiner und diskreter Ihre Klassen sind, desto einfacher ist es, Dinge zu ändern: Denken Sie an LEGO.
get(index)
,add()
,size()
,remove(index)
, undremove(Object)
. Unter Verwendung der vorgeschlagenen Technik muss die Klasse, die diese ArrayList enthält, über fünf öffentliche Methoden verfügen, um nur an die innere Sammlung zu delegieren. Und der Zweck dieser Klasse im Programm besteht höchstwahrscheinlich darin, diese ArrayList nicht zu kapseln, sondern etwas anderes zu tun. Die ArrayList ist nur ein Detail. [...]