Ich versuche zu verstehen, wie Polymorphismus in einem realen Projekt verwendet wird, aber ich kann nur das klassische Beispiel (oder etwas Ähnliches) für eine Animal
Elternklasse mit einer Methode speak()
und viele Kindklassen finden, die diese Methode außer Kraft setzen Sie können die Methode speak()
für jedes der untergeordneten Objekte aufrufen , zum Beispiel:
Animal animal;
animal = dog;
animal.speak();
animal = cat;
animal.speak();
object-oriented
data-structures
polymorphism
Christopher
quelle
quelle
if(x is SomeType) DoSomething()
kann es sich lohnen, Polymorphismus zu verwenden, wenn Sie häufig überladene Methoden ausführen, um mit verschiedenen Typen umzugehen, und wenn der Code ähnlich ist, oder wenn Sie häufig schreiben . Für mich ist Polymorphismus eine Entscheidung, die dem Zeitpunkt ähnelt, an dem eine separate Methode erstellt werden soll. Wenn ich feststelle, dass ich den Code einige Male wiederholt habe, baue ich ihn normalerweise in eine Methodeif object is this type do this
um Refactoring und Hinzufügen einer Schnittstelle oder Klasse.Antworten:
Stream ist ein großartiges Beispiel für Polymorphismus.
Stream repräsentiert eine "Folge von Bytes, die gelesen oder geschrieben werden können". Diese Sequenz kann jedoch aus einer Datei, aus dem Speicher oder aus vielen Arten von Netzwerkverbindungen stammen. Oder es kann als Dekorator dienen, der vorhandene Datenströme umschließt und die Bytes auf eine Art und Weise umwandelt, beispielsweise durch Verschlüsselung oder Komprimierung.
Auf diese Weise muss sich der Client, der Stream verwendet, nicht darum kümmern, woher die Bytes kommen. Nur damit sie der Reihe nach gelesen werden können.
Einige würden sagen
Stream
, dass es sich um ein falsches Beispiel für Polymorphismus handelt, da es viele "Funktionen" definiert, die von den Implementierungsprogrammen nicht unterstützt werden, z. Oder mangelndes Suchen. Dies ist jedoch nur eine Frage der Komplexität, daStream
sie in viele Teile unterteilt werden kann, die unabhängig voneinander implementiert werden könnten.quelle
Stream
s sind mein absolutes Lieblingsbeispiel für Polymorphismus. Ich versuche nicht einmal mehr, den Menschen das fehlerhafte Tier-, Säugetier- und Hundemodell beizubringenStream
.Ein typisches spielebezogenes Beispiel wäre eine Basisklasse
Entity
, die gemeinsame Mitglieder wiedraw()
oder bereitstelltupdate()
.Für ein reineres datenorientiertes Beispiel könnte es eine Basisklasse geben,
Serializable
die ein gemeinsamessaveToStream()
und einloadFromStream()
.quelle
Es gibt verschiedene Arten von Polymorphismus, wobei derjenige von Interesse normalerweise Laufzeitpolymorphismus / dynamischer Versand ist.
Eine sehr allgemeine Beschreibung des Laufzeitpolymorphismus ist, dass ein Methodenaufruf abhängig vom Laufzeittyp seiner Argumente unterschiedliche Aktionen ausführt: Das Objekt selbst ist für die Auflösung eines Methodenaufrufs verantwortlich. Dies ermöglicht eine enorme Flexibilität.
Eine der gebräuchlichsten Möglichkeiten, diese Flexibilität zu nutzen, ist die Abhängigkeitsinjektion , z. B. um zwischen verschiedenen Implementierungen zu wechseln oder Scheinobjekte zum Testen zu injizieren. Wenn ich im Voraus weiß, dass es nur eine begrenzte Anzahl von Auswahlmöglichkeiten gibt, könnte ich versuchen, sie mit Bedingungen fest zu codieren, zB:
Dies macht es schwierig, dem Code zu folgen. Die Alternative besteht darin, eine Schnittstelle für diese Foo-Operation einzuführen und eine normale Implementierung und eine Scheinimplementierung dieser Schnittstelle zu schreiben und zur Laufzeit in die gewünschte Implementierung einzufügen. "Abhängigkeitsinjektion" ist ein komplizierter Begriff für "Übergeben des richtigen Objekts als Argument".
In der Praxis arbeite ich derzeit an einem Problem mit maschinellem Lernen. Ich habe einen Algorithmus, der ein Vorhersagemodell erfordert. Aber ich möchte verschiedene Algorithmen für maschinelles Lernen ausprobieren. Also habe ich eine Schnittstelle definiert. Was brauche ich von meinem Vorhersagemodell? Bei gegebener Eingabestichprobe die Vorhersage und ihre Fehler:
Mein Algorithmus verwendet eine Factory-Funktion, die ein Modell trainiert:
Ich habe jetzt verschiedene Implementierungen der Modellschnittstelle und kann sie gegeneinander vergleichen. Eine dieser Implementierungen verwendet tatsächlich zwei andere Modelle und kombiniert sie zu einem verstärkten Modell. Also dank dieser Schnittstelle:
Ein klassischer Anwendungsfall für Polymorphismus ist die grafische Benutzeroberfläche. In einem GUI-Framework wie Java AWT / Swing /… gibt es verschiedene Komponenten . Die Komponentenschnittstelle / Basisklasse beschreibt Aktionen wie das Malen auf den Bildschirm oder das Reagieren auf Mausklicks. Viele Komponenten sind Container, die Unterkomponenten verwalten. Wie könnte sich ein solcher Container selbst zeichnen?
Hier muss der Container nicht im Voraus die genauen Typen der Unterkomponenten kennen - solange sie mit der
Component
Schnittstelle übereinstimmen, kann der Container einfach die polymorphepaint()
Methode aufrufen . Dies gibt mir die Freiheit, die AWT-Klassenhierarchie mit beliebigen neuen Komponenten zu erweitern.Es gibt viele wiederkehrende Probleme in der Softwareentwicklung, die durch die Anwendung des Polymorphismus als Technik gelöst werden können. Diese wiederkehrenden Problem-Lösungs-Paare werden Entwurfsmuster genannt , und einige von ihnen sind im gleichnamigen Buch zusammengefasst. In diesem Buch wäre mein Modell des injizierten maschinellen Lernens eine Strategie , die ich verwende, um „eine Familie von Algorithmen zu definieren, jede einzelne zu kapseln und austauschbar zu machen“. Das Java-AWT-Beispiel, in dem eine Komponente Unterkomponenten enthalten kann, ist ein Beispiel für einen Verbund .
Es muss jedoch nicht für jedes Design Polymorphismus verwendet werden (über die Aktivierung der Abhängigkeitsinjektion für Komponententests hinaus, was ein wirklich guter Anwendungsfall ist). Die meisten Probleme sind ansonsten sehr statisch. Infolgedessen werden Klassen und Methoden häufig nicht für den Polymorphismus verwendet, sondern lediglich als bequeme Namespaces und für die hübsche Syntax von Methodenaufrufen. ZB bevorzugen viele Entwickler Methodenaufrufe
account.getBalance()
gegenüber weitgehend gleichwertigen FunktionsaufrufenAccount_getBalance(account)
. Das ist ein perfekter Ansatz, es ist nur so, dass viele Methodenaufrufe nichts mit Polymorphismus zu tun haben.quelle
In den meisten UI-Toolkits sind viele Vererbungen und Polymorphismen zu sehen.
Beispielsweise
Button
erbt im JavaFX-UI-Toolkit, vonButtonBase
wemLabeled
erbt, vonControl
wemRegion
erbt, vonParent
wem erbt, von wem erbt, von wemNode
erbtObject
. Viele Ebenen überschreiben einige Methoden aus den vorherigen.Wenn Sie möchten, dass diese Schaltfläche auf dem Bildschirm angezeigt wird, fügen Sie sie einer hinzu
Pane
, die alles akzeptiert, was SieNode
als Kind erben . Aber woher weiß ein Fenster, was mit einer Schaltfläche zu tun ist, wenn es nur als generisches Knotenobjekt betrachtet wird? Das Objekt könnte alles sein. Das Fenster kann dies tun, da der Button die Methoden von Node mit einer beliebigen knopfspezifischen Logik neu definiert. Der Bereich ruft nur die in Node definierten Methoden auf und überlässt den Rest dem Objekt selbst. Dies ist ein perfektes Beispiel für angewandten Polymorphismus.UI-Toolkits haben eine sehr hohe reale Bedeutung, sodass sie sowohl aus akademischen als auch aus praktischen Gründen nützlich sind.
UI-Toolkits haben jedoch auch einen erheblichen Nachteil: Sie sind in der Regel sehr umfangreich . Wenn ein Neophyte-Softwareentwickler versucht, die internen Abläufe eines allgemeinen UI-Frameworks zu verstehen, trifft er häufig auf über hundert Klassen , von denen die meisten sehr esoterischen Zwecken dienen. „Was zum Teufel ist ein
ReadOnlyJavaBeanLongPropertyBuilder
? Ist es wichtig? Muß ich habe zu verstehen , was es ist gut?“ Anfänger können sich in diesem Kaninchenbau leicht verirren. So können sie entweder vor Schrecken fliehen oder an der Oberfläche bleiben, wo sie nur die Syntax lernen und versuchen, nicht zu genau darüber nachzudenken, was tatsächlich unter der Haube passiert.quelle
Obwohl es hier bereits schöne Beispiele gibt, besteht ein anderes darin, Tiere durch Geräte zu ersetzen:
Device
kann seinpowerOn()
,powerOff()
,setSleep()
und kanngetSerialNumber()
.SensorDevice
all dies tun können, und bieten polymorphe Funktionen wiegetMeasuredDimension()
,getMeasure()
,alertAt(threashhold)
undautoTest()
.getMeasure()
wird nicht in der gleichen Weise für einen Temperatursensor, einen Lichtdetektor, einen Schalldetektor oder einen Volumensensor implementiert. Und natürlich kann jeder dieser spezialisierteren Sensoren einige zusätzliche Funktionen haben.quelle
Presentation ist eine sehr häufige Anwendung, die wahrscheinlich häufigste ist ToString (). Das ist im Grunde Animal.Speak (): Sie weisen ein Objekt an, sich zu manifestieren.
Allgemeiner gesagt sagt man einem Objekt, dass es "seine Sache machen" soll. Denken Sie an Save, Load, Initialize, Dispose, ProcessData, GetStatus.
quelle
Meine erste praktische Anwendung des Polymorphismus war die Implementierung von Heap in Java.
Ich hatte eine Basisklasse mit der Implementierung von Methoden insert, removeTop, bei der der Unterschied zwischen max und min Heap nur darin besteht, wie Methodenvergleiche funktionieren.
Wenn ich also MaxHeap und MinHeap haben wollte, konnte ich einfach Vererbung verwenden.
quelle
Hier ist ein reales Szenario für den Polymorphismus von Webanwendungen / Datenbanktabellen :
Ich verwende Ruby on Rails, um Web-Apps zu entwickeln, und eine Sache, die viele meiner Projekte gemeinsam haben, ist die Möglichkeit, Dateien (Fotos, PDFs usw.) hochzuladen. So können beispielsweise
User
mehrere Profilbilder in a undProduct
viele Produktbilder in a vorhanden sein. Beide haben das Verhalten, Bilder hochzuladen und zu speichern sowie die Größe zu ändern, Thumbnails zu generieren usw. Um trocken zu bleiben und das Verhalten für zu teilenPicture
, möchten wirPicture
polymorph machen, so dass es zu beidenUser
und gehören kannProduct
.In Rails würde ich meine Modelle so gestalten:
und eine Datenbankmigration zum Erstellen der
pictures
Tabelle:Die Spalten
imageable_id
undimageable_type
werden von Rails intern verwendet. Enthält im Grundeimageable_type
den Namen der Klasse ("User"
,"Product"
usw.) undimageable_id
ist die ID des zugeordneten Datensatzes. Alsoimageable_type = "User"
undimageable_id = 1
wäre der Rekord in derusers
Tabelle mitid = 1
.Auf diese Weise können wir beispielsweise auf
user.pictures
die Bilder des Benutzers zugreifen und die Bilderproduct.pictures
eines Produkts abrufen. Dann wird das gesamte bildbezogene Verhalten in derPhoto
Klasse eingekapselt (und nicht für jedes Modell, das Fotos benötigt, eine separate Klasse), sodass die Dinge trocken bleiben.Lesen Sie weiter: Polymorphe Assoziationen an Schienen .
quelle
Es gibt viele Sortieralgorithmen wie Bubble-Sortierung, Insert-Sortierung, Quick-Sortierung, Heap-Sortierung usw. und sie haben unterschiedliche Komplexität. Welche Sortierung optimal ist, hängt von verschiedenen Faktoren ab (z. B. Größe des Arrays).
Der mit einer Sortierschnittstelle versehene Client kümmert sich nur darum, ein Array als Eingabe bereitzustellen und dann ein sortiertes Array zu empfangen. Während der Laufzeit kann abhängig von bestimmten Faktoren eine geeignete Sortierimplementierung verwendet werden. Dies ist ein Beispiel aus der Praxis, wo Polymorphismus verwendet wird.
Was ich oben beschrieben habe, ist ein Beispiel für Laufzeit-Polymorphismus, wohingegen das Überladen von Methoden ein Beispiel für das Kompilieren von Zeit-Polymorphsim ist, wobei die Kompilierbarkeit von I / P- und O / P-Parametertypen und der Anzahl der Parameter abhängt, dass der Aufrufer zur Kompilierbarkeit selbst die richtige Methode verwendet.
Hoffe das klärt sich.
quelle