Ich weiß, das scheint eine seltsame Frage zu sein, da der Punkt, an dem zwei oder mehr Objekte dieselbe Klasse teilen, darin besteht, dass sie dasselbe Verhalten haben, dh dass ihre Methoden identisch sind.
Ich bin jedoch gespannt, ob es OOP-Sprachen gibt, mit denen Sie die Methoden von Objekten auf dieselbe Weise neu definieren können, wie Sie unterschiedliche Werte für ihre Felder zuweisen können. Das Ergebnis wären Objekte aus derselben Klasse, die nicht mehr genau dasselbe Verhalten aufweisen.
Wenn ich mich nicht irre, kannst du dieses JavaScript? Zusammen mit dieser Frage frage ich, warum sollte jemand dies tun wollen?
object-oriented
programming-languages
Niko Bellic
quelle
quelle
setClickHandler()
Methode zu übergeben und verschiedene Instanzen derselben Klasse dazu zu bringen, sehr unterschiedliche Dinge zu tun. In Sprachen, die keine passenden Lambda-Ausdrücke haben, ist es einfacher, eine neue anonyme Unterklasse nur für einen neuen Handler zu erstellen. In der Vergangenheit galt das Überschreiben von Methoden als Kennzeichen einer neuen Klasse, während das Festlegen der Werte von Attributen nicht als Kennzeichen galt. Insbesondere bei Handlerfunktionen wirken sich die beiden Methoden jedoch sehr ähnlich aus, sodass die Unterscheidung zu einem Krieg um Wörter wird.Antworten:
Methoden in den meisten (klassenbasierten) OOP-Sprachen sind nach Typ festgelegt.
JavaScript ist prototypbasiert und nicht klassenbasiert. Daher können Sie Methoden für einzelne Instanzen außer Kraft setzen, da es keine klare Unterscheidung zwischen "Klasse" und Objekt gibt. In Wirklichkeit ist eine "Klasse" in JavaScript ein Objekt, das wie eine Vorlage für die Funktionsweise der Instanzen aussieht.
Jede Sprache, die erstklassige Funktionen wie Scala, Java 8, C # (über Delegates) usw. zulässt, kann sich so verhalten, als hätten Sie Methodenüberschreibungen pro Instanz. Sie müssten ein Feld mit einem Funktionstyp definieren und es dann in jeder Instanz überschreiben.
Scala hat eine andere Möglichkeit; In Scala können Sie Objekt-Singletons erstellen (mithilfe des Schlüsselworts object anstelle des Schlüsselworts class), um Ihre Klasse zu erweitern und die Methoden zu überschreiben. Dies führt zu einer neuen Instanz dieser Basisklasse mit Überschreibungen.
Warum sollte jemand das tun? Es könnte Dutzende von Gründen geben. Es könnte sein, dass das Verhalten für mich enger definiert werden muss, als es die Verwendung verschiedener Feldkombinationen erlauben würde. Es könnte auch den Code entkoppelt und besser organisiert halten. Im Allgemeinen halte ich diese Fälle jedoch für seltener und es gibt oft eine einfachere Lösung mit Feldwerten.
quelle
Es ist schwierig, die Motivation für Ihre Frage zu erraten, und daher können einige mögliche Antworten Ihr wirkliches Interesse ansprechen oder nicht.
Selbst in einigen Nicht-Prototypensprachen ist es möglich, diesen Effekt anzunähern.
In Java entspricht beispielsweise eine anonyme innere Klasse ziemlich genau dem, was Sie beschreiben. Sie können eine Unterklasse des Originals erstellen und instanziieren und dabei nur die Methode oder Methoden überschreiben, die Sie möchten. Die resultierende Klasse wird
instanceof
die ursprüngliche Klasse sein, wird jedoch nicht dieselbe Klasse sein.Warum möchten Sie das tun? Ich denke, dass mit Java 8 Lambda-Ausdrücken viele der besten Anwendungsfälle verschwinden. Zumindest mit früheren Java-Versionen kann so eine Verbreitung von trivialen Klassen mit engem Verwendungszweck vermieden werden. Das heißt, wenn Sie eine große Anzahl verwandter Anwendungsfälle haben, die sich nur in einer winzigen funktionalen Weise unterscheiden, können Sie sie (fast) im Handumdrehen erstellen, wobei die Verhaltensunterschiede zum gewünschten Zeitpunkt hinzugefügt werden.
Das heißt, selbst vor J8 kann dies oft überarbeitet werden, um die Differenz in ein oder drei Felder zu verschieben und sie in den Konstruktor einzufügen. Mit J8 kann natürlich die Methode selbst in die Klasse eingebunden werden, obwohl es eine Versuchung geben kann, dies zu tun, wenn ein anderes Refactoring möglicherweise sauberer (wenn nicht so cool) ist.
quelle
Sie haben nach einer Sprache gefragt, die instanzbezogene Methoden bereitstellt. Es gibt bereits eine Antwort für Javascript. Sehen wir uns also an, wie es in Common Lisp gemacht wird, wo Sie EQL-Spezialisierer verwenden können:
Warum?
EQL-Spezialisierer sind nützlich, wenn das Argument, das dem Versand unterliegt, einen Typ haben soll, für den
eql
es Sinn macht: eine Zahl, ein Symbol usw. Im Allgemeinen brauchen Sie es nicht, und Sie müssen einfach so viele Unterklassen wie definieren benötigt von Ihrem Problem. Manchmal müssen Sie jedoch nur nach einem Parameter versenden, bei dem es sich beispielsweise um ein Symbol handelt: Eincase
Ausdruck ist in der Dispatching-Funktion auf die bekannten Fälle beschränkt, während Methoden jederzeit hinzugefügt und entfernt werden können.Die Spezialisierung auf Instanzen ist auch für Debugging-Zwecke hilfreich, wenn Sie vorübergehend überprüfen möchten, was mit einem bestimmten Objekt in Ihrer ausgeführten Anwendung geschieht.
quelle
Sie können dies auch in Ruby mit Singleton-Objekten tun:
Produziert:
Genau so verfährt Ruby mit Klassen- und Modulmethoden. Beispielsweise:
Definiert tatsächlich eine Singleton-Methode
hello
für dasClass
ObjektSomeClass
.quelle
extend
eigentlich nur die Singleton-Klasse für das Objekt erstellt und dann das Modul in die Singleton-Klasse importiert wird.Sie können sich Methoden pro Instanz vorstellen, mit denen Sie zur Laufzeit Ihre eigene Klasse zusammenstellen können. Dies kann eine Menge Kleber-Code eliminieren, der keinen anderen Zweck hat, als zwei Klassen zusammenzufügen, um miteinander zu sprechen. Mixins sind eine etwas strukturiertere Lösung für die gleichen Probleme.
Du leidest ein wenig unter leidest Paradoxon Blubs , im Wesentlichen, dass es schwierig ist, den Wert eines Sprachfeatures zu erkennen, bis Sie dieses Feature in einem echten Programm verwendet haben. Suchen Sie also nach Gelegenheiten, bei denen Sie glauben, dass sie funktionieren könnten, probieren Sie sie aus und sehen Sie, was passiert.
Suchen Sie in Ihrem Code nach Gruppen von Klassen, die sich nur durch eine Methode unterscheiden. Suchen Sie nach Klassen, deren einziger Zweck darin besteht, zwei andere Klassen in unterschiedlichen Kombinationen zu kombinieren. Suchen Sie nach Methoden, die nichts anderes tun, als einen Aufruf an ein anderes Objekt weiterzuleiten. Suchen Sie nach Klassen, die mithilfe komplexer Erstellungsmuster instanziiert werden . Dies sind alles mögliche Kandidaten, die durch Methoden pro Instanz ersetzt werden müssen.
quelle
Andere Antworten haben gezeigt, wie dies ein gemeinsames Merkmal von dynamischen objektorientierten Sprachen ist und wie es trivial in einer statischen Sprache emuliert werden kann, die erstklassige Funktionsobjekte enthält (z. B. Delegate in c #, Objekte, die operator () in c ++ überschreiben). . In statischen Sprachen, in denen eine solche Funktion fehlt, ist dies schwieriger, kann aber dennoch durch die Verwendung einer Kombination aus dem Strategiemuster und einer Methode erreicht werden, bei der die Implementierung einfach an die Strategie delegiert wird. Dies ist in der Tat dasselbe, was Sie in c # mit Delegaten tun würden, aber die Syntax ist etwas chaotischer.
quelle
Sie können so etwas in C # und den meisten ähnlichen Sprachen tun.
quelle
Obwohl in einer Sprache wie Java alle Instanzen einer Klasse die gleichen Methoden haben müssen, ist es konzeptionell möglich, durch Hinzufügen einer zusätzlichen Indirektionsebene, möglicherweise in Kombination mit verschachtelten Klassen, den Eindruck zu erwecken, dass dies nicht der Fall ist.
Wenn eine Klasse
Foo
beispielsweise eine statische abstrakte verschachtelte Klasse definieren kann,QuackerBase
die eine Methode enthältquack(Foo)
, sowie mehrere andere statische verschachtelte Klassen, von denenQuackerBase
jede eine eigene Definition von hatquack(Foo)
, dann kann es sein, dass die äußere Klasse ein Feldquacker
vom TypQuackerBase
hat Setzen Sie dieses Feld, um eine (möglicherweise einzelne) Instanz einer ihrer verschachtelten Klassen zu identifizieren. Wenn dies geschehen ist,quacker.quack(this)
wird beim Aufrufen der Befehl ausgeführtquack
Methode der Klasse ausgeführt, deren Instanz diesem Feld zugewiesen wurde.Da dies ein weit verbreitetes Muster ist, enthält Java Mechanismen, um die entsprechenden Typen automatisch zu deklarieren. Solche Mechanismen tun eigentlich nichts, was mit virtuellen Methoden und optional verschachtelten statischen Klassen nicht möglich wäre, aber sie reduzieren die Menge an Boilerplate, die erforderlich ist, um eine Klasse zu erstellen, deren einziger Zweck es ist, eine einzelne Methode im Auftrag von auszuführen eine andere Klasse.
quelle
Ich glaube, das ist die Definition einer "dynamischen" Sprache wie Ruby, Groovy & Javascript (und vielen vielen anderen). Dynamisch bezieht sich (zumindest teilweise) auf die Fähigkeit, das Verhalten einer Klasseninstanz im laufenden Betrieb dynamisch neu zu definieren.
Es ist im Allgemeinen keine großartige OO-Praxis, aber für viele dynamische Sprachprogrammierer stehen OO-Prinzipien nicht an erster Stelle.
Es vereinfacht einige knifflige Vorgänge wie Monkey-Patching, bei denen Sie möglicherweise eine Klasseninstanz optimieren, um mit einer geschlossenen Bibliothek auf eine Weise zu interagieren, die sie nicht vorausgesehen haben.
quelle
Ich sage nicht, dass es eine gute Sache ist, aber das ist in Python trivial möglich. Ich kann keinen guten Anwendungsfall auf den Kopf stellen, aber ich bin mir sicher, dass es sie gibt.
quelle