Dies ist nur ein Dummy-Code, der einen echten Code darstellt, den ich habe (der Kürze halber ist das nur ein Beispielcode)
Ich habe 2 ASP MVC-Apps, die ziemlich ähnliche Dinge tun.
Sicherheit / Sitzungslogik (zusammen mit anderen Dingen) passiert in beiden gleich.
Ich habe die Basisfunktionalität von beiden in eine neue Bibliothek abstrahiert, die beide erben. Wenn die Basisklasse Dinge benötigt, die nur aus der eigentlichen Implementierung erhalten werden können, implementiere ich diese als abstrakte Methoden. In meinem obigen Beispiel muss ich Benutzerinformationen aus einer Datenbank abrufen, um die Authentifizierung in der Basisbibliothek durchzuführen. Um die richtige DB für die Anwendung zu erhalten, habe ich eine abstrakte Methode GetRepository
, die das Repository für die Anwendung zurückgibt. Von hier aus kann die Basis eine Methode auf dem Repo aufrufen, um Benutzerinformationen zu erhalten und mit der Validierung fortzufahren, oder was auch immer.
Wenn eine Änderung an der Authentifizierung vorgenommen werden muss, muss ich nur eine Lib aktualisieren, anstatt die Duplikate in beiden zu kopieren. Kurz gesagt, wenn Sie einige Funktionen implementieren möchten, aber nicht alle, dann funktioniert eine abstrakte Klasse großartig. Wenn Sie keine Funktionalität implementieren möchten, verwenden Sie eine Schnittstelle.
Bei Verwendung des Vorlagenmethodenmusters ist die Verwendung der abstrakten Methode sehr üblich. Sie können damit das Skelett eines Algorithmus definieren und Unterklassen bestimmte Schritte des Algorithmus modifizieren oder verfeinern, ohne seine Struktur zu verändern.
Werfen Sie einen Blick auf ein "reales" Beispiel aus der Template-Pattern-Seite von doFactory .
Die .NET-Klassen Stream sind ein gutes Beispiel. Die Stream-Klasse enthält grundlegende Funktionen, die von allen Streams implementiert werden, und dann stellen bestimmte Streams spezifische Implementierungen für die tatsächliche Interaktion mit I / O bereit.
Die Grundidee besteht darin, die abstrakte Klasse zu verwenden, um das Skelett und die grundlegende Funktionalität bereitzustellen und die konkrete Implementierung so zu lassen, dass genau die benötigten Details bereitgestellt werden.
Angenommen, Sie haben eine Schnittstelle mit ... +20 Methoden, zum Beispiel eine List-Schnittstelle.
%Vor%Wenn jemand eine Implementierung für diese Liste bereitstellen muss, muss er jedes Mal die Methode +20 implementieren.
Eine Alternative wäre, eine abstrakte Klasse zu haben, die die meisten Methoden bereits implementiert und den Entwickler nur einige davon implementieren lässt.
Zum Beispiel
%Vor%Um eine nicht änderbare Liste zu implementieren, muss der Programmierer diese Klasse nur erweitern und Implementierungen für die Methoden get (int index) und size () bereitstellen
In dieser Situation: get
und size
sind abstrakte Methoden , die der Entwickler implementieren muss. Der Rest der Funktionalität ist möglicherweise bereits implementiert.
Während diese Implementierung absurd aussieht, wäre es nützlich, eine Variable zu initialisieren:
%Vor%um Nullzeiger zu vermeiden.
Verwendet für eine selbst gemachte Version von Tetris, wo jeder Typ Tetraminos eine Kindklasse der Tetramino-Klasse war.
Nehmen Sie beispielsweise an, dass Sie einige Klassen haben, die den Zeilen in Ihrer Datenbank entsprechen. Vielleicht möchten Sie, dass diese Klassen als gleich gelten, wenn ihre ID gleich ist, denn so funktioniert die Datenbank. Sie könnten also die ID abstrahieren, weil Sie damit Code schreiben könnten, der die ID verwendet, aber nicht implementieren, bevor Sie die ID in den konkreten Klassen kennen. Auf diese Weise vermeiden Sie die Implementierung der gleichen equals -Methode in allen Entitätsklassen.
%Vor%Ich bin kein C # -Typ. Darf ich Java benutzen? Das Prinzip ist das gleiche. Ich habe dieses Konzept in einem Spiel verwendet. Ich berechne den Rüstungswert verschiedener Monster sehr unterschiedlich. Ich nehme an, ich könnte sie verschiedene Konstanten verfolgen lassen, aber das ist konzeptionell viel einfacher.
%Vor%Sie können eine abstrakte Methode (anstelle einer Schnittstelle) immer dann verwenden, wenn Sie eine Basisklasse haben, die tatsächlich einige Implementierungscodes enthält. Für eine oder mehrere Methoden gibt es jedoch keine sinnvolle Standardimplementierung:
%Vor%