1unitedpower: Klasse aus Datenbank füllen, danach die Klasse verarbeiten

Beitrag lesen

Ich wähle für die Antwort mal eine paar sehr herbe Worte, formuliert als Angriff, Übertreibung als Stilmittel. Lass sie nicht bis zum Gemüt vordringen, das könnte sich darüber aufregen, was ich aber nicht beabsichtige. Los geht's:

*g* darauf lasse ich mich ein.

Wofür hältst du dich eigentlich, dass du meinst den Verwender vor etwas beschützen zu müssen? Meinst du die Verwender sind nicht gut genug im Programmieren und Code-Verstehen, die potentiellen Auswirkungen zu erkennen?

Für einen verantwortungsbewussten Menschen. Wenn ich mit dem Wagen liegen bleibe, stelle ich auch ein Warndreieck auf. Wenn ich ein Auto baue, baue ich Sicherheitsgurte und Airbags ein.

Warum willst du sie davon abhalten, dass sie sich ins Knie schießen, wenn sie es denn unbedingt wollen?

Weil ich nicht glaube, dass sich jemand wirklich ins Knie schießen will. Ich bin nicht der Typ, der jemandem zum Fischen eine Schusswaffe in die Hand drückt, ich drücke ihm eine Angel in die Hand.

Gehen wir zum Beispiel von einer Klasse A mit zwei öffentlichen Methoden aus:

[...]

Klasse B erbt von A und überschreibt die Methode bar:

[...]

Frage, zu welchem Wert evaluiert die zweite Zeile in folgendem Code?

[...]

Wenn A aber intern $this->bar() aufruft, dann führt das zu einer Exception.

Wenn es denn so wichtig ist, dass foo() unbeeinflusst vom Zustand von bar() korrekt arbeitet, dann kann man das eigentliche Geschehen auch in eine private Methode auszulagern versuchen, die dann von foo() und bar() aufgerufen wird. Wenn jemand das öffentliche bar() überschreibt, kann er das tun, ohne die Abhängigkeit zu beeinflussen.

Könnte man, das lässt sich aber nicht statisch überprüfen. Die Klasse A muss mit mehr Aufwand implementiert werden, damit beim Ableiten keine Nebenwirkungen auftreten. Und selbst wenn das gelingt, dann muss man bei der Implementierung von B immer noch in die Implementierung von Klasse A gucken, weil die Eigenschaften von Klasse A sich nicht statisch verifizieren lassen. final dagegen hat eine statische Semantik.

Der Knackpunkt ist, dass man als Autor der Klasse B nicht wissen kann, wie sie sich verhalten wird, wenn nur eine einzige Methode überschrieben wird, außer man sieht sich die Implementierung der Elternklasse an.

Ja, das sollte man tun, wenn man etwas verwenden möchte.

Nö, sollte man nicht müssen. Program to an interface, not an implementation.

Wenn es die Dokumentation nicht hergibt, notfalls mit dem Blick in die Quellen oder mit dem Decompiler. PHP selbst ist da jedoch nicht ganz so zugänglich. .NET-Code lässt sich einfacher in lesbaren C#-Code rückübersetzen. Außerdem ist da vieles sowieso im Original C# gewesen und nicht artfremdes C wie bei PHP. Aber dein Code ist ja PHP, und wenn du ihn nicht verschleiert und verschlüsselt auslieferst, hat man da ja die Chance, ihn sich anzusehen.

Ja, die Möglichkeit besteht. Ich will es aber nicht zu einer Voraussetzung machen, in die Implementierung zu gucken, um die Schnittstelle zu nutzen.

Zum aderen sorge ich mit final auch dafür, dass die Schnittstelle homogen genutzt wird, ich gebe dem Verwender eine klare Intention zu ihrem Gebrauch mit.

Jein. Das ist lediglich ein einzelnes Wort. Es muss nicht immer Intention hinter einem bestimmten Gebrauch stecken. Auch "haben wir schon immer so gemacht" kann der Grund sein. Man kann da nicht immer zweifelsfrei erkennen, was dahintersteckt. Ein erklärender Text in der Dokumentation, warum das da so wichtig ist, und vielleicht auch, was die Folgen sein könnten, ist da meist viel verständlicher. Gerade mit weniger Erfahrung sieht man nur die Tatsache, dass es final oder sealed ist, weiß aber vielleicht noch so nicht recht, warum man sowas macht.

ACK.

Damals habe ich das Problem gelöst, indem ich mir den Code der Erweiterungen kopiert und so modifiziert habe, dass sie kompositionell zusammenarbeiteten, das war ein Aha-Moment für mich.

Das ist schön für dich, aber für dich war es ein Erkenntnisprozess. Einfach nur ein final dastehen zu haben, setzt diesen Prozess nicht in Gang. Es wirkt eher wie ein Verbotsschild, dessen Grund man sich vielleicht erschließen kann, vielleicht aber auch nicht.

Das ist auch richtig. Aber ich verhindere, dass NutzerInnen meines Code in diese Falle tappen.

Abgesehen davon, dass ich für mich noch keinen Anwendungsfall gefunden habe, wo ich eine solche Unveränderbarkeit als notwendig erachtet hätte, will ich dem nicht komplett die Nützlichkeit absprechen.

Ich sehe das umgekehrt: Wenn ich eine Klasse für Vererbung öffne, dann füge ich der Schnittstelle eine gehörige Portion Komplexität hinzu, sie gewinnt aber nicht an Ausdrucksstärke. Nur durch das Zulassen von Vererbung werden ja nicht auf magische Weise neue Anwendungsfälle abgedeckt. Wenn ich also eine Klasse schon öffne, und die gesteigerte Komplexität in Kauf nehme, dann sollte ich auch einen konkreten Anwendungsfall damit abdecken wollen. Anderenfalls, YAGNI.