Ist es völlig gegen die Java-Methode, strukturähnliche Objekte zu erstellen?
class SomeData1 {
public int x;
public int y;
}
Ich kann eine Klasse mit Accessoren und Mutatoren sehen, die eher Java ähneln.
class SomeData2 {
int getX();
void setX(int x);
int getY();
void setY(int y);
private int x;
private int y;
}
Die Klasse aus dem ersten Beispiel ist notatorisch praktisch.
// a function in a class
public int f(SomeData1 d) {
return (3 * d.x) / d.y;
}
Dies ist nicht so bequem.
// a function in a class
public int f(SomeData2 d) {
return (3 * d.getX()) / d.getY();
}
Antworten:
Dies ist ein häufig diskutiertes Thema. Der Nachteil beim Erstellen öffentlicher Felder in Objekten besteht darin, dass Sie keine Kontrolle über die darauf festgelegten Werte haben. In Gruppenprojekten, in denen viele Programmierer denselben Code verwenden, ist es wichtig, Nebenwirkungen zu vermeiden. Außerdem ist es manchmal besser, eine Kopie des Feldobjekts zurückzugeben oder es irgendwie zu transformieren usw. Sie können solche Methoden in Ihren Tests verspotten. Wenn Sie eine neue Klasse erstellen, werden möglicherweise nicht alle möglichen Aktionen angezeigt. Es ist wie defensives Programmieren - eines Tages können Getter und Setter hilfreich sein, und es kostet nicht viel, sie zu erstellen / zu verwenden. Sie sind also manchmal nützlich.
In der Praxis haben die meisten Felder einfache Getter und Setter. Eine mögliche Lösung würde so aussehen:
Update: Es ist sehr unwahrscheinlich, dass die Unterstützung von Eigenschaften in Java 7 oder vielleicht jemals hinzugefügt wird. Andere JVM-Sprachen wie Groovy, Scala usw. unterstützen diese Funktion jetzt. - Alex Miller
quelle
=
, was meiner Meinung nach den Code sauberer macht.x
, die zwei verschiedene Dinge sind, ist das keine gute Idee. IMHO, das ist ein schlechter Vorschlag, da er bei menschlichen Lesern zu Verwirrung führen könnte. Grundprinzip: Lassen Sie einen Leser nicht doppelt nehmen; Machen Sie deutlich, was Sie sagen - Verwenden Sie unterschiedliche Namen für unterschiedliche Entitäten. Auch wenn der Unterschied lediglich darin besteht, einen Unterstrich voranzustellen. Verlassen Sie sich nicht auf die umgebende Interpunktion, um die Entitäten zu unterscheiden.Es scheint, dass viele Java-Benutzer nicht mit den Sun Java-Codierungsrichtlinien vertraut sind, nach denen es durchaus angebracht ist, eine öffentliche Instanzvariable zu verwenden, wenn die Klasse im Wesentlichen eine "Struktur" ist, wenn Java "Struktur" unterstützt (wenn kein Verhalten vorliegt).
Die Leute neigen dazu zu denken, dass Getter und Setter der Java-Weg sind, als ob sie das Herz von Java sind. Das ist nicht so. Wenn Sie die Sun Java-Codierungsrichtlinien befolgen und in geeigneten Situationen öffentliche Instanzvariablen verwenden, schreiben Sie tatsächlich besseren Code, als ihn mit unnötigen Gettern und Setzern zu überladen.
Java Code Conventions von 1999 und noch unverändert.
10.1 Zugriff auf Instanz- und Klassenvariablen bereitstellen
Machen Sie keine Instanz- oder Klassenvariablen ohne guten Grund öffentlich. Oft müssen Instanzvariablen nicht explizit gesetzt oder abgerufen werden - was häufig als Nebeneffekt von Methodenaufrufen auftritt.
Ein Beispiel für geeignete öffentliche Instanzvariablen ist der Fall, in dem die Klasse im Wesentlichen eine Datenstruktur ohne Verhalten ist. Mit anderen Worten, wenn Sie eine Struktur anstelle einer Klasse verwendet hätten (wenn Java die Struktur unterstützt), sollten Sie die Instanzvariablen der Klasse öffentlich machen .
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
quelle
Verwenden Sie wirklich gesunden Menschenverstand. Wenn Sie etwas haben wie:
Dann macht es wenig Sinn, sie in Getter und Setter einzuwickeln. Sie werden niemals eine x, y-Koordinate in ganzen Pixeln auf andere Weise speichern. Getter und Setter werden Sie nur verlangsamen.
Auf der anderen Seite mit:
Möglicherweise möchten Sie die Art und Weise ändern, wie ein Saldo zu einem späteren Zeitpunkt berechnet wird. Dies sollte wirklich Getter und Setter verwenden.
Es ist immer besser zu wissen, warum Sie bewährte Verfahren anwenden, damit Sie wissen, wann es in Ordnung ist, die Regeln zu ändern.
quelle
(-5, -5)
möglicherweise nicht einstellt eine gute Idee. :-)Um Bedenken hinsichtlich der Veränderlichkeit auszuräumen, können Sie x und y als endgültig deklarieren. Beispielsweise:
Wenn Sie Code aufrufen, der versucht, in diese Felder zu schreiben, wird der Kompilierungszeitfehler "Feld x wird als endgültig deklariert; kann nicht zugewiesen werden" angezeigt.
Der Client-Code kann dann die in Ihrem Beitrag beschriebene "Kurzhand" -Komfort haben
quelle
case
Ausdruck, der auf ein solches Instanzfeld verweist, habe ich erhaltenCase expressions must be constant expressions
. Wie geht das um? Was ist das idiomatische Konzept hier?Verwenden Sie keine
public
FelderVerwenden Sie keine
public
Felder, wenn Sie das interne Verhalten einer Klasse wirklich umbrechen möchten. Nehmen wirjava.io.BufferedReader
zum Beispiel. Es hat das folgende Feld:skipLF
wird in allen Lesemethoden gelesen und geschrieben. Was ist, wenn eine externe Klasse, die in einem separaten Thread ausgeführt wird, den Status während eines Lesevorgangs in böswilliger Absicht geändert hatskipLF
?BufferedReader
wird auf jeden Fall drunter und drüber gehen.Verwenden Sie
public
FelderNehmen Sie diese
Point
Klasse zum Beispiel:Dies würde die Berechnung des Abstands zwischen zwei Punkten sehr schmerzhaft machen.
Die Klasse hat kein anderes Verhalten als einfache Getter und Setter. Es ist akzeptabel, öffentliche Felder zu verwenden, wenn die Klasse nur eine Datenstruktur darstellt und kein Verhalten hat und niemals haben wird (Thin Getter und Setter werden hier nicht als Verhalten betrachtet). Es kann besser so geschrieben werden:
Reinigen!
Aber denken Sie daran: Nicht nur Ihre Klasse muss kein Verhalten haben, sondern es sollte auch keinen Grund geben, sich auch in Zukunft zu verhalten.
(Genau dies wird in dieser Antwort beschrieben. So zitieren Sie "Code-Konventionen für die Java-Programmiersprache: 10. Programmierpraktiken" :
Die offizielle Dokumentation akzeptiert diese Praxis also auch.)
Wenn Sie besonders sicher sind, dass Mitglieder der oben genannten
Point
Klasse unveränderlich sein sollten, können Sie einfinal
Schlüsselwort hinzufügen , um dies durchzusetzen:quelle
Die Struktur, die Sie als Beispiel angeben, ist übrigens bereits in der Java-Basisklassenbibliothek als vorhanden
java.awt.Point
. Es hat x und y als öffentliche Felder, überzeugen Sie sich selbst .Wenn Sie wissen, was Sie tun, und andere in Ihrem Team davon wissen, ist es in Ordnung, öffentliche Felder zu haben. Sie sollten sich jedoch nicht darauf verlassen, da sie Kopfschmerzen verursachen können, wie bei Fehlern, die mit Entwicklern zusammenhängen, die Objekte verwenden, als wären sie stapelzugeordnete Strukturen (Java-Objekte werden immer als Referenzen und nicht als Kopien an Methoden gesendet).
quelle
public final
Feld erfolgen, wie in Brians Antwort, oder durch einen öffentlichen Getter, aber keinen öffentlichen Setter. Das heißt, ob man Felder oder Accessoren verwendet, ist unerheblich.Re: aku, izb, John Topley ...
Achten Sie auf Veränderlichkeitsprobleme ...
Es mag sinnvoll erscheinen, Getter / Setter wegzulassen. In einigen Fällen kann es tatsächlich in Ordnung sein. Das eigentliche Problem mit dem hier gezeigten vorgeschlagenen Muster ist die Veränderlichkeit.
Das Problem besteht darin, dass Sie eine Objektreferenz mit nicht endgültigen öffentlichen Feldern übergeben. Alles andere mit dieser Referenz kann diese Felder ändern. Sie haben keine Kontrolle mehr über den Status dieses Objekts. (Überlegen Sie, was passieren würde, wenn Strings veränderlich wären.)
Es wird schlecht, wenn dieses Objekt ein wichtiger Teil des internen Status eines anderen ist. Sie haben gerade die interne Implementierung verfügbar gemacht. Um dies zu verhindern, muss stattdessen eine Kopie des Objekts zurückgegeben werden. Dies funktioniert, kann jedoch einen massiven GC-Druck durch Tonnen von einmal erstellten Einwegkopien verursachen.
Wenn Sie öffentliche Felder haben, sollten Sie die Klasse schreibgeschützt machen. Fügen Sie dem Konstruktor die Felder als Parameter hinzu und markieren Sie die Felder als endgültig. Stellen Sie andernfalls sicher, dass Sie den internen Status nicht verfügbar machen. Wenn Sie neue Instanzen für einen Rückgabewert erstellen müssen, stellen Sie sicher, dass dieser nicht übermäßig aufgerufen wird.
Siehe: " Effective Java " von Joshua Bloch - Punkt 13: Unveränderlichkeit begünstigen.
PS: Denken Sie auch daran, dass alle JVMs heutzutage die getMethod nach Möglichkeit optimieren, was zu nur einer einzigen Feldleseanweisung führt.
quelle
Ich habe dies in einigen Projekten versucht, mit der Theorie, dass Getter und Setter den Code mit semantisch bedeutungslosem Cruft überladen und dass andere Sprachen mit konventionellem Verstecken von Daten oder Aufteilen von Verantwortlichkeiten (z. B. Python) gut zurechtkommen.
Wie andere oben erwähnt haben, gibt es zwei Probleme, auf die Sie stoßen und die nicht wirklich behoben werden können:
Und dies ist im besten Fall das Szenario, in einem eigenständigen privaten Projekt zu arbeiten. Sobald Sie das Ganze in eine öffentlich zugängliche Bibliothek exportieren, werden diese Probleme noch größer.
Java ist sehr ausführlich und dies ist eine verlockende Sache. Tu es nicht.
quelle
Wenn der Java-Weg der OO-Weg ist, dann verstößt das Erstellen einer Klasse mit öffentlichen Feldern gegen die Prinzipien des Versteckens von Informationen, die besagen, dass ein Objekt seinen eigenen internen Status verwalten sollte. (Da ich Sie also nicht nur mit Jargon ausspucke, besteht ein Vorteil des Versteckens von Informationen darin, dass die internen Funktionen einer Klasse hinter einer Schnittstelle verborgen sind. Angenommen, Sie wollten den Mechanismus ändern, mit dem Ihre Strukturklasse eines ihrer Felder gespeichert hat. Sie müssen wahrscheinlich zurückgehen und alle Klassen ändern, die die Klasse verwenden ...)
Sie können auch nicht die Unterstützung für JavaBean-Klassen nutzen, die mit der Benennung kompatibel sind. Dies kann schaden, wenn Sie beispielsweise die Klasse auf einer JavaServer-Seite verwenden, die mit Expression Language geschrieben wurde.
Der JavaWorld-Artikel Warum Getter- und Setter-Methoden böse sind, könnte Sie auch interessieren, wenn Sie darüber nachdenken, wann Sie keine Accessor- und Mutator-Methoden implementieren sollten.
Wenn Sie eine kleine Lösung schreiben und die Menge an Code minimieren möchten, ist der Java-Weg möglicherweise nicht der richtige - ich denke, es hängt immer von Ihnen und dem Problem ab, das Sie lösen möchten.
quelle
An dieser Art von Code ist nichts auszusetzen, vorausgesetzt, der Autor weiß, dass es sich um Strukturen (oder Daten-Shuttles) anstelle von Objekten handelt. Viele Java-Entwickler können den Unterschied zwischen einem wohlgeformten Objekt (nicht nur einer Unterklasse von java.lang.Object, sondern einem echten Objekt in einer bestimmten Domäne) und einer Ananas nicht erkennen. Ergo schreiben sie am Ende Strukturen, wenn sie Objekte benötigen und umgekehrt.
quelle
Das Problem bei der Verwendung des öffentlichen Feldzugriffs ist das gleiche Problem wie bei der Verwendung von new anstelle einer Factory-Methode. Wenn Sie später Ihre Meinung ändern, sind alle vorhandenen Anrufer fehlerhaft. Aus Sicht der API-Evolution ist es daher normalerweise eine gute Idee, in die Kugel zu beißen und Getter / Setter zu verwenden.
Ein Ort, an dem ich den anderen Weg gehe, ist, wenn Sie den Zugriff auf die Klasse stark kontrollieren, beispielsweise in einer inneren statischen Klasse, die als interne Datenstruktur verwendet wird. In diesem Fall ist es möglicherweise viel klarer, den Feldzugriff zu verwenden.
Übrigens ist es nach Aussage von e-bartek sehr unwahrscheinlich, dass IMO die Unterstützung von Eigenschaften in Java 7 hinzugefügt wird.
quelle
Ich verwende dieses Muster häufig beim Erstellen privater innerer Klassen, um meinen Code zu vereinfachen, würde jedoch nicht empfehlen, solche Objekte in einer öffentlichen API verfügbar zu machen. Im Allgemeinen ist es umso besser, je häufiger Sie Objekte in Ihrer öffentlichen API unveränderlich machen können, und es ist nicht möglich, Ihr 'strukturähnliches' Objekt unveränderlich zu erstellen.
Abgesehen davon würde ich, selbst wenn ich dieses Objekt als private innere Klasse schreiben würde, immer noch einen Konstruktor bereitstellen, um den Code zum Initialisieren des Objekts zu vereinfachen. Es ist einfach chaotisch, 3 Codezeilen zu haben, um ein verwendbares Objekt zu erhalten, wenn man es tut.
quelle
Eine sehr sehr alte Frage, aber lassen Sie mich noch einen kurzen Beitrag leisten. Java 8 führte Lambda-Ausdrücke und Methodenreferenzen ein. Lambda-Ausdrücke können einfache Methodenreferenzen sein und keinen "wahren" Körper deklarieren. Sie können ein Feld jedoch nicht in eine Methodenreferenz "konvertieren". So
ist nicht legal, aber
ist.
quelle
data -> data.x
, was immer noch vernünftig istIch sehe den Schaden nicht, wenn Sie wissen, dass es immer eine einfache Struktur sein wird und dass Sie niemals Verhalten daran anhängen wollen.
quelle
Dies ist eine Frage zum objektorientierten Design, nicht zur Sprache Java. Im Allgemeinen empfiehlt es sich, Datentypen innerhalb der Klasse auszublenden und nur die Methoden bereitzustellen, die Teil der Klassen-API sind. Wenn Sie interne Datentypen verfügbar machen, können Sie diese in Zukunft nie mehr ändern. Wenn Sie sie ausblenden, besteht Ihre einzige Verpflichtung gegenüber dem Benutzer in den Rückgabe- und Argumenttypen der Methode.
quelle
Hier erstelle ich ein Programm zur Eingabe von Name und Alter von 5 verschiedenen Personen und führe eine Auswahlsortierung durch (altersmäßig). Ich habe eine Klasse verwendet, die als Struktur fungiert (wie die Programmiersprache C), und eine Hauptklasse, um die gesamte Operation auszuführen. Hierunter richte ich den Code ein ...
Der obige Code ist fehlerfrei und getestet ... Kopieren Sie ihn einfach und fügen Sie ihn in Ihre IDE ein und ... Sie wissen und was ??? :) :)
quelle
Sie können eine einfache Klasse mit öffentlichen Feldern und ohne Methoden in Java erstellen, aber es ist immer noch eine Klasse und wird immer noch syntaktisch und in Bezug auf die Speicherzuweisung wie eine Klasse behandelt. Es gibt keine Möglichkeit, Strukturen in Java wirklich zu reproduzieren.
quelle
Manchmal verwende ich eine solche Klasse, wenn ich mehrere Werte von einer Methode zurückgeben muss. Natürlich ist ein solches Objekt von kurzer Dauer und mit sehr eingeschränkter Sichtbarkeit, daher sollte es in Ordnung sein.
quelle
Wie bei den meisten Dingen gibt es die allgemeine Regel und dann gibt es bestimmte Umstände. Wenn Sie eine geschlossene, erfasste Anwendung ausführen, damit Sie wissen, wie ein bestimmtes Objekt verwendet wird, können Sie mehr Freiheit ausüben, um Sichtbarkeit und / oder Effizienz zu fördern. Wenn Sie eine Klasse entwickeln, die von anderen außerhalb Ihrer Kontrolle öffentlich verwendet wird, lehnen Sie sich an das Getter / Setter-Modell. Verwenden Sie wie bei allen Dingen nur den gesunden Menschenverstand. Es ist oft in Ordnung, eine erste Runde mit der Öffentlichkeit zu machen und sie später in Getter / Setter zu ändern.
quelle
Mit der aspektorientierten Programmierung können Sie Zuweisungen oder Abrufe abfangen und ihnen eine Abfanglogik hinzufügen. Ich schlage vor, dies ist der richtige Weg, um das Problem zu lösen. (Die Frage, ob sie öffentlich oder geschützt oder paketgeschützt sein sollen, ist orthogonal.)
Sie beginnen also mit nicht abgefangenen Feldern mit dem richtigen Zugriffsqualifizierer. Wenn Ihre Programmanforderungen wachsen, fügen Sie eine Logik hinzu, um möglicherweise zu validieren, eine Kopie des zurückgegebenen Objekts zu erstellen usw.
Die Getter / Setter-Philosophie verursacht Kosten für eine große Anzahl einfacher Fälle, in denen sie nicht benötigt werden.
Ob der Aspektstil sauberer ist oder nicht, ist etwas qualitativ. Ich würde es einfach finden, nur die Variablen in einer Klasse zu sehen und die Logik separat zu betrachten. Tatsächlich ist das Grundprinzip für eine apect-orientierte Programmierung, dass viele Probleme sich überschneiden und eine Unterteilung in den Klassenkörper selbst nicht ideal ist (Protokollierung ist ein Beispiel - wenn Sie alles protokollieren möchten, was Java von Ihnen verlangt Schreiben Sie eine ganze Reihe von Gettern und halten Sie sie synchron, aber AspectJ ermöglicht Ihnen einen Einzeiler.
Das Problem der IDE ist ein roter Hering. Es ist weniger das Tippen als vielmehr das Lesen und die visuelle Verschmutzung, die durch get / sets entstehen.
Anmerkungen scheinen auf den ersten Blick der aspektorientierten Programmierung ähnlich zu sein, erfordern jedoch eine ausführliche Aufzählung von Punktschnitten durch Anhängen von Anmerkungen, im Gegensatz zu einer prägnanten Wildcard-ähnlichen Punktschnitt-Spezifikation in AspectJ.
Ich hoffe, dass das Bewusstsein für AspectJ verhindert, dass sich Menschen vorzeitig für dynamische Sprachen entscheiden.
quelle