![]() |
Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
Hallo Community...
Vor einiger Zeit habe ich die S.O.L.I.D Prinzipien kennengelernt zu denen auch das Liskovsches Substitutionsprinzip zählt. So wie Wikipedia es zusammenfast: Zitat:
Dann kann man zwischen "reintroduce" und "override" wählen um die Methode zu überschreiben. "override" nur wenn die Elternmethode "virtual" oder "dynamic" war. Ohne Schlüsselwort gibt der Compiler eine Warnung, welche man selbstverständlich nicht möchte. Der traditionelle Weg eine Methode einer Elternklasse zu überschreiben ist "override". Hierbei wird die Methode der vererbten Klasse aufgerufen und nicht die der Elternklasse, wenn man eine Instanz der Kindklasse als Basisklasse 'casted' oder meint ein Element der Elternklasse vor sich zu haben.
Delphi-Quellcode:
Meine Frage: Wird hier gegen das Liskovsche - Prinzip verstoßen? Normalerweise müsste doch die say-Methode des Tpapa aufgerufen werden wenn dem Prinzip, dass
// type
Tpapa = class public { public declarations } procedure say; dynamic; end; Tsohn = class(Tpapa) public { public declarations } procedure say; override; end; // Implementation var Sohn : Tsohn; begin Sohn := Tsohn.Create; Tpapa(Sohn).say; Zitat:
Mit reintroduce anstelle von override bekommt man das erwartete Ergebnis... Wieso verstoßen wir (oder bin Ich damit alleine) dann gegen das Prinzip? Oder ist das Prinzip veraltet / nur ein Ideal? |
AW: Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
Es geht darum, dass TSohn.Say auch was sagt und nicht was komplett anderes macht, was derjenige, der die Say Methode aufruft, nicht erwartet.
|
AW: Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
OK, abgesehn davon, daß virtual meist besser geeignet ist, als dynamic ...
Im Prinzip geht es doch beim OOP um Erweiterung/Vervollständigung? Siehe TStrings oder TStream. Diese Basisklassen stellen eine allgemeingültige Schnittstelle zur Verfügung. Hinter den Methoden steckt eine gewisse Funktionalität und die nachfahren überschreiben nun diese Methoden, um die spezifischen Anforderungen des jeweiligen Zielsystems bereitzustellen. Wenn ich mir dieses LSP so durchlese, dann bekomm ich das Gefühl, das weder Reintroduce, Virtual, Dynamic, noch Override erlaubt seien. Also es dürften keine Funktionen verdeckt oder überschrieben werden. Du könntest also nur noch Klassen um neue andersbenamte Methoden erweitern und dürftest keine der Vorgängerfunktionen verändern. Und schon hast du mit der OOP ein Problem, denn sowas wie mit TStream und TStrings wäre nicht möglich. (außer bei den Interfaces) |
AW: Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
Zitat:
Delphi-Quellcode:
procedure TPapa.Say;
begin Writeln('Hallo! Wie geht''s?'); end; procedure TSohn.Say; begin Writeln('Eyh Alter! Was geht ab?'); end; |
AW: Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
Oder noch krasser:
Delphi-Quellcode:
procedure TPapa.Say;
begin Writeln('Hallo! Wie geht''s?'); end; procedure TSohn.Say; begin FormatLocalHardDrives; end; |
AW: Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
Vielen Dank himitsu und Stevie für eure Antworten... es beschäftigt mich, da Ich mich noch in meiner Ausbildung befinde.
Demnach sollte Ich bei Erweiterung/Vervollständigung die Methode überschreiben. laut Stevie: Ansonsten auch darauf achten, dass Ich in der überschriebenen Methode nicht etwas völlig anderes mache. Vielleicht nimmt sich noch Jemand die Zeit und schreib etwas aus seiner Erfahrung dazu? Danke, Jonas :D DaddyH beweißt Humor =) Dann würde Ich aber voher noch inherited aufrufen.
Delphi-Quellcode:
Writeln('Hallo! Wie geht''s?');
procedure TSohn.Say;
begin inherited; FormatLocalHardDrives; end; :!: Boom Dann gehts es mir garantiert scheiße :D |
AW: Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
Nee, eben kein inherited. Es ging ja darum, dass TSohn.Say etwas komplett anderes tut als TPapa.Say. Mit inherited würde die Methode ja lediglich erweitert, was ja regelkonform wäre.
|
AW: Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
Zitat:
Also, das LSP sagt ja nur etwas über das erwartete Verhalten aus. Dies ist aber eben i.A. in der Implementation der Methode versteckt und nicht in irgendwelchen semantischen Feinheiten. In meinem Beispiel wäre das LSP nicht verletzt, bei obigem bei gleicher Semantik (override) allerdings schon. |
AW: Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
Das Geraffelt mit dem virtual/dynamic und reintroduce ist - mal runter gebrochen - eigentlich nur DocumentationByCode.
Darum gibt der Compiler ja auch nur Warnungen und keine Fehler aus. (virtual und dynamic bedeuten von der Logik her ein und dasselbe, der Compiler optimiert nur anders) Bei der Definition einer (Basis-)Klasse macht man sich ja im Allgemeinen Gedanken, wie da was funktionieren soll. Um nun zu dokumentieren, wo man abweichende oder konkrete Implementierungen erwartet gibt es halt die Schlüsselwörter
Delphi-Quellcode:
für eine (nicht zwingende) abweichende oder zwingend konkrete
virtual;
Delphi-Quellcode:
Implementierung.
virtual; abstract;
Methoden ohne diese Schlüsselwörter werden somit als "ich erwarte nicht, dass diese Methoden in den abgeleiteten Klassen verändert werden" markiert. Steht man aber nun doch vor dem Problem eine solche Methode doch überschreiben zu müssen, dann wird nicht die Basis-Klasse verändert (Methode als virtual deklarieren), sondern man markiert in der abgeleiteten Klasse diese Methode mit
Delphi-Quellcode:
.
reintroduce
Einfach nur um zu dokumentieren "ja, ich weiß ich soll die nicht ableiten, aber in diesem speziellen Fall ist aber zwingend notwendig" Ach ja und das mit dem LSP meint ja nur, dass man eben nicht überrascht werden soll, wie in diesem Beispiel:
Delphi-Quellcode:
TKoerper = class
function Gewicht : real; virtual; abstract; function Oberflaeche : real; virtual; abstract; end; TKugel = class( TKoerper ) function Gewicht : real; override; function Oberflaeche : real; override; end; function TKugel.Gewicht : real; begin Result := {Formel für die Oberfläche}; end; function TKugel.Oberflaeche : real; begin Result := {Formel für das Gewicht}; end; |
AW: Reintroduce / Override bei Virtual / Dynamic im Bezug auf OOP - Prinzipien
Ich wollte ja auch ein Negativbeispiel bringen. Wenn eine Methode einer Elternklasse z.B. SaveToFile heißt, dann erwarte ich, dass etwas in einer Datei gespeichert wird. Wenn nun aber jemand diese Methode in einer abgeleiteten Klasse überschreibt, dabei kein inherited aufruft und stattdessen etwas komplett anderes tut, dann verstößt er damit gegen das angesprochene Prinzip.
[edit] Hoppla, da hat sich noch ein Post dazwischengemogelt. [/edit] |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:16 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz