2010-01-30 3 views
9

Ich verstehe die Motivation für die einzelnen Methoden einer Klasse sealed/final, aber welcher Zweck verbietet vollständig die Vererbung von der Klasse dienen? Während das Überschreiben bestimmter Methoden dazu führen kann, dass schlimme Dinge passieren, kann ich nicht erkennen, dass die Vererbung von Ihrer Klasse, um Verhalten hinzuzufügen, ohne bestehendes Verhalten zu überschreiben, jemals eine schlechte Sache sein könnte. Wenn Sie wirklich alles in Ihrer Klasse nicht überschreiben möchten, warum sollten Sie nicht jede Methode endgültig machen, aber dennoch die Vererbung zulassen, um das Verhalten zu ergänzen?Warum würdest du eine ganze Klasse versiegeln/endgültig machen?

+0

Im Falle von java.util.UUID finde ich die Unfähigkeit, Unterklasse frustrierend. –

Antwort

3

Ein Organisation/Software-Entwicklerteam möchte möglicherweise bestimmte Codierungsstandards durchsetzen. Um beispielsweise die Lesbarkeit zu verbessern, möchten sie möglicherweise nur, dass das Attribut X der Klasse Y mit der Methode Z und sonst nichts geändert wird. Wenn die Klasse nicht final wäre, könnte ein Entwickler die Klasse Y erweitern und die Methode W hinzufügen, die X auf eine andere Weise modifizieren und Verwirrung und Verzögerungen verursachen könnte, wenn es darum geht, den geschriebenen Code zu verstehen.

+0

Macht Attribut X nicht die gleiche Sache privat? – Dalius

+1

@Dalius Sogar mit X private, vielleicht ist es wünschenswert, dass nur ein direkter Aufruf von Z auf einem Y-Objekt X betrifft. Wenn eine Klasse W Z überschreibt, dann können Sie X durch einen Aufruf von Z auf einem W-Objekt ändern, was den anfänglichen Wunsch, X zu ändern, nur durch einen Z-Methodenaufruf direkt von einem Y-Objekt unterbricht. Ich persönlich habe solche Situation nie gesehen, aber ich denke, dass es passieren kann. –

4

Es gibt einige gute Diskussionen darüber in der Frage „Warum String final in Java ist“: Why is String class declared final in Java?

Die grundlegende Zusammenfassung in diesem Fall ist, ist String unveränderlich, und wenn es subclassed werden könnte, die Unterklasse könnte mach es veränderbar.

2

Denken Sie darüber nach: Sie haben die letzten 3 Monate an einer Basisklasse für Ihr eigenes Framework gearbeitet, die andere nutzen werden, und die gesamte Konsistenz des Frameworks basiert auf dem in dieser Klasse geschriebenen Code und modifiziert Diese Klasse kann Fehler, Fehler und Fehlverhalten Ihres Frameworks verursachen. Wie verhindern Sie, dass Ihre großen Programmierer diese erweitern und eine ihrer Methoden außer Kraft setzen?

Darüber hinaus gibt es Klassen, die unveränderlich sein sollen, wie die java.lang.String-Klasse in Java, die sie erweitern und ihr Verhalten ändern könnte.

Schließlich manchmal eine Klasse oder Methode als Finale wird die Leistung zu erhöhen, aber ich habe es nie getestet, und sehe keinen Grund auf der Erde eine Klasse/Methode endgültig für eine sehr sehr kleine Leistungssteigerung, die gleich ist Null im Vergleich zu der Zeit, die benötigt wird, um andere Dinge im Programm zu tun.

+0

1. Die Frage besteht darin, zuzulassen, dass Unterklassen Verhalten hinzufügen. Ich verstehe, warum Sie das Außerkraftsetzen verbieten möchten. 2. Wenn eine Klasse 3 Monate zum Schreiben braucht, ist es wahrscheinlich viel zu viel. – dsimcha

+0

Nehmen Sie nicht 3 Monate literarisch, die Idee war eine wichtige Klasse, in einem fragilen Kontext, und wo jede andere Klasse erwartet, dass sie ein bestimmtes Verhalten befolgen wird. –

3

Allgemeiner kann eine Klasse final gemacht werden, um die Invarianten zu erhalten, die sie funktionieren lassen. Ich empfehle Joshua Blochs "Effektives Java" für eine hervorragende Diskussion über diese und verwandte Themen.

0

Ich denke, es kommt darauf an.

Wenn ich eine interne Anwendung habe, würde ich nicht das Finale auf Klassenebene standardmäßig verwenden. Der Code wird einfach zu unübersichtlich. Unter Umständen ist der finale Modifikator sogar wirklich nervig, wenn ich sicher refaktorisieren will (siehe programming by difference). In einigen Fällen machte die "Standard-End-Manie" große Probleme, als ich versuchte, umzugestalten.

Wenn ich andererseits ein API/Framework entwickle, in dem Code eher extension-getrieben ist, würde ich final für Klassen 'aggressiver' verwenden. Hier kann eine falsche Erweiterung ein großes Problem darstellen und der "letzte" Modifikator ist ein sicherer Weg, um solche Programmierfehler zu vermeiden.

Aber ich bin einfach dagegen zu sagen, verwenden Sie "final" standardmäßig wie viele tun. Es hat oft mehr Nachteile als Vorteile. Für mich sollten Standardeinstellungen "vernünftige und gängigere Einstellungen" sein.

0

Soweit ich weiß, geht es um die Erhaltung von Invarianten.In einer analogen Situation könnten Sie zum Beispiel Ihre Attribute öffentlich machen, aber dann würden Sie die Kontrolle über ihre Werte verlieren, weil Clients sie direkt ändern könnten, wodurch einige Eigenschaften zerstört würden, die Sie beibehalten möchten. Auf die gleiche Weise, wie Sie Clients den Zugriff auf einige (die meisten tatsächlichen) Felder direkt untersagen, um einige Invarianten beizubehalten, machen Sie auch Ihre Klasse/Methode endgültig, um einige Invarianten beizubehalten.

Ein gängiges Beispiel sehe ich muss mit Unveränderlichkeit tun, die gebrochen werden kann, wenn eine Klasse nicht endgültig ist.

Das Problem ist nicht wirklich, wenn ein Benutzer eine Klasse erweitert und nutzt sie nur in seinem System, mit seiner eigenen „mess“ lebt isoliert von alles andere. Das eigentliche Problem hat damit zu tun, dass Klassen/Methoden/Attribute/Objekte/... nicht isoliert existieren.

Angenommen, Sie haben eine Sammlung von Klassen CC1, die zu einem bestimmten Ziel kollaborieren, und eine dieser Klassen CC1_A sollte nur unveränderliche Objekte (oder eine andere Invariante, die Sie möchten) "produzieren". Dann fahren Sie fort und erweitern CC1_A, wodurch CC2_AX entsteht (erweitertes A in einer zweiten Klassensammlung). Was Sie jetzt tun können, ist die Verwendung von CC1-Zeug, das CC2_AX passiert, wo ein CC1_A benötigt wird. CC1 wurde jedoch unter der Annahme erstellt, dass CC1_A-Objekte unveränderlich sind, aber Ihre CC2_AX-Objekte nicht (davon ausgehend, dass sie nicht nur dem Beispiel entsprechen). Dies kann zu ernsthaften Problemen in Ihrem Programm führen. Ein solches Problem kann sogar intern in einer Klasse auftreten. Zum Beispiel werden CC1_A-Methoden wahrscheinlich annehmen, dass CC1_A-Objekte unveränderlich sind, daher können Methoden von CC2_AX, die von CC1_A kamen, möglicherweise fehlschlagen, weil CC2_AX die immutability-Eigenschaft bricht.

In unseren Systemen, heute haben wir viele Klassen und eine Menge von dem, was wir tun implizit geht. Wir denken also nicht immer an die Invarianten, die wir beibehalten möchten. Das macht die Dinge nicht einfacher.

By the way, einige andere Invarianten gehören Dinge wie:

  • Die Sortiermethode stabil sein sollte.
  • Die <wie> Methode verwendet den < anderen wie > Algorithmus.
  • Diese <Klasse> Liste Implementierung sollte einfach verkettete Implementierung wie beschrieben < einige Stelle > verwenden.

Es geht weiter und weiter. Einige Klassen sind nur nützlich, weil sie stärkere Invarianten beibehalten (z. B. die Verwendung eines bestimmten Algorithmus), und die Erweiterung ermöglicht es den Benutzern, solche Dinge leicht zu durchbrechen. Und ein Grund, warum das alles ein Problem ist, hat damit zu tun, dass diese Dinge nicht isoliert leben.

Verwandte Themen