Verstößt es gegen das Open-Closed-Prinzip, eine Konstante zu aktualisieren, die einen realen Wert darstellt?


10

Ich habe eine Klasse, die das jährliche Nettoeinkommen der Arbeiter berechnet. Es hat eine Konstante, die einen Steuerprozentsatz darstellt. Aber eines Tages hat sich der Steuersatz geändert, daher muss ich den Code korrigieren.

Zeigt das Festlegen dieser Konstante einen Verstoß gegen das Open-Closed-Prinzip an , da postuliert wird, dass eine Klasse für Änderungen geschlossen werden sollte?


10
Software ändert sich, weil sich die reale Welt ändert. Auf der anderen Seite ist es weniger ein Verstoß gegen das Open-Closed-Prinzip, einen Steuerprozentsatz zu einer Konstanten zu machen, als vielmehr eine unwissende Sache. Der Steuerprozentsatz ist ein offensichtlich veränderbarer Posten, der zur Laufzeit gebunden werden sollte.
Richard Chambers

4
Ich stimme Richard vollkommen zu. Wenn Sie den Code ändern müssen, um diese "Konstante" zu beheben, ist OCP das geringste Ihrer Probleme.
Robert Harvey

3
Was eine Verletzung von OCP darstellt, ist höchst subjektiv und das Ganze ist sowieso etwas veraltet (da die Vererbung von Implementierungen keine bewährte Methode mehr ist). Dies ist eine typische Frage, bei der Sie erraten müssen, was die Person, die die Frage stellt, denkt.
Robert Bräutigam

2
@DocBrown: Was ist eine "neue Anforderung"? Wenn Sie mir Code zeigen, kann ich auf neue Anforderungen hinweisen, die definitiv eine Änderung des Codes erfordern, unabhängig davon, wie OCP-konform Sie ihn erstellen. Zurück zur Frage: Wenn der Entwickler den Geschäftsexperten danach gefragt hat und nicht erwartet wurde, dass sich der Steuersatz mehr als einmal alle paar Jahre ändert, macht es keinen Sinn, ihn konfigurierbar oder injizierbar zu machen. Halten Sie es einfach und bereiten Sie sich auf das vor, was Sie wissen . Und für diese Dinge machen Sie es sicher außerhalb der Klasse. Es kommt also darauf an .
Robert Bräutigam

1
@ RobertBräutigam: Mein Punkt ist, es gibt meiner Meinung nach keine "OCP-konform", es gibt nur "OCP-konform im Kontext bestimmter Kategorien von Anforderungen". Es kann sicherlich eine gewisse Subjektivität geben, welchen Kategorien eine Komponente "OCP-konform" sein sollte. In dem in dieser Frage beschriebenen Fall wurde, so wie ich es verstehe, bereits eine sich ändernde Anforderung festgestellt, so dass diese "einkommensberechnende Klasse" der OCP im Kontext dieser spezifischen Anforderung eindeutig nicht gehorcht.
Doc Brown

Antworten:


14

Das OCP kann besser verstanden werden, wenn man an Klassen oder Komponenten denkt, die von einem Anbieter A in einer Art Black-Box-Bibliothek zur Verwendung durch die Benutzer B, C und D bereitgestellt werden (beachten Sie, dass dies nur ein mentales Modell ist, das ich aus Gründen der Klarheit verwende). Es spielt keine Rolle, ob in Wirklichkeit der einzige Benutzer der Klasse A selbst ist.

Wenn B, C und D die bereitgestellten Klassen für verschiedene Anwendungsfälle verwenden oder wiederverwenden können, ohne dass der Quellcode der Bibliothek geändert werden muss, erfüllt die Komponente die OCP ( in Bezug auf eine Kategorie von Anwendungsfällen ). Es gibt verschiedene Mittel, um dies zu erreichen, wie z

  • Vererbbarkeit der Klasse (normalerweise in Verbindung mit dem Muster der Vorlagenmethode oder dem Strategiemuster)

  • durch Bereitstellen von "Injektionspunkten" für die Abhängigkeitsinjektion

  • durch Bereitstellen von Konfigurationsparametern für die Klasse oder Komponente (z. B. durch einen Konstruktorparameter "Steuerprozentsatz" wie in Ihrem Fall oder durch Verwendung eines anderen Konfigurationsmechanismus)

  • möglicherweise andere Mittel, abhängig von der Programmiersprache oder dem Ökosystem

Die typischen Beispiele, die Sie in Lehrbüchern finden, sind oft vom ersten oder zweiten Typ (ich denke, weil der dritte Typ in den Augen der Autoren dieses Buches zu trivial ist, um erwähnt zu werden).

Wie Sie sehen, hat dies nichts damit zu tun, eine Änderung des Quellcodes durch Anbieter A zu verbieten (z. B. zur Fehlerbehebung, Optimierung oder zum Hinzufügen abwärtskompatibler neuer Funktionen), die in keiner Beziehung zum OCP steht. In der OCP geht es darum, wie A die Schnittstelle und die Granularität der Komponenten in der Bibliothek gestaltet, sodass unterschiedliche Wiederverwendungsszenarien (wie die Wiederverwendung mit unterschiedlichen Steuersätzen) nicht automatisch Änderungsanforderungen hervorrufen.

Trotz allem, was Ihnen hier gesagt wird, lautet die Antwort eindeutig "Ja" . Dies wäre eine Verletzung der OCP.

BEARBEITEN: Zwischendurch hat jemand einen detaillierten Blog-Beitrag zu genau diesem Thema geschrieben. Obwohl Teile davon besser formuliert sein könnten (wie Derek Elkins betonte), scheint der Autor im Allgemeinen meinen Standpunkt zu teilen, dass "Erfüllung der OCP" keine absolute Eigenschaft ist, sondern etwas, das nur im Zusammenhang mit bestimmten bewertet werden kann Kategorien von Anforderungsänderungen.


OK, bei OCP geht es darum, erweiterbares Verhalten für verschiedene Anwendungsfälle mit einem von drei von Ihnen aufgelisteten Mitteln bereitzustellen, oder? Aber was ist, wenn das Beispiel eines OP impliziert, dass sich etwas Grundlegendes ändern wird? Ich weiß nicht, aus welchem ​​Land OP stammt, aber in meinem Land ändert sich der Steuersatz nicht sehr oft. Es war ein schlechtes Beispiel, aber vielleicht wurde es absichtlich in einer Konstanten extrahiert, um den Punkt zu betonen. Ich bin mir ziemlich sicher, dass es nicht konfigurierbar oder erweiterbar sein sollte. Vielleicht lautete die Frage also "Dies hat nichts damit zu tun, eine Änderung des Quellcodes durch Anbieter A zu verbieten".
Vadim Samokhin

Zumindest habe ich das so verstanden. Der arme Kerl, der seine akzeptierte Antwort gelöscht hat, hat das auch getan, denke ich. Sie haben es aus einem etwas anderen Blickwinkel gesehen - ich verstehe Ihren Standpunkt und stimme ihm zu. Aber es scheint, dass der klügste Kommentar von @Robert Bräutigam gegeben wurde. Bis jetzt habe ich nicht bemerkt, dass OCP DAS subjektiv ist.
Vadim Samokhin

1
Ich denke, wenn mir jemals dieselbe Frage gestellt wird, gibt es eine Frage, die ich als Antwort stellen sollte: "Soll dieses Verhalten irgendwie erweitert oder konfiguriert werden?". Wenn ja - dann ist die direkte Änderung einer Klasse selbst eine Verletzung von OCP. Wenn nein - dann ist OCP in dieser Situation einfach nicht anwendbar.
Vadim Samokhin

1
@Zapadlo: Ich denke, wenn eine Komponente das OCP für eine Klasse von Anforderungen erfüllt, ist dies nicht sehr subjektiv - es ist in den meisten Fällen ziemlich klar, ob eine neue Anforderung eine Änderung des Quellcodes einer Komponente erfordert oder ob die Komponente diese Anforderung unterstützt ". Die möglichen Ansätze zur Implementierung sind nicht auf die ersten drei Mittel beschränkt, die ich aufgelistet habe, siehe meine Bearbeitung. Ihr Begriff der Subjektivität kann verursacht werden, weil die OCP nur einen irreführenden Namen hat und in vielen Lehrbüchern ziemlich schlecht erklärt wird.
Doc Brown

Meine Vorstellung von Subjektivität wurde durch die Tatsache verursacht, dass ich nicht vollständig verstanden habe, was Sie gesagt haben - aber ich denke, jetzt. Vielen Dank für aufschlussreiche Kommentare und Ihre Antwort.
Vadim Samokhin

4

Wie andere sagen, würde die Arbeitereinkommensklasse im Idealfall die Parametrisierung der Konstante ermöglichen, wodurch diese Klasse von diesem Wert unabhängig wird.

Letztendlich kann die aufrufende Anwendung auch eine Parametrisierung in Bezug auf die externe Konfiguration (z. B. eine Datei) ermöglichen. Sobald wir eine externe Konfiguration haben, können wir den Steuersatz ändern. Beachten Sie jedoch, dass die Anwendung neu gestartet werden muss, wenn die Konfigurationsdatei beim Start nur einmal gelesen wird, damit die aktualisierten Steuerprozentsätze wirksam werden Verstand. Wir könnten eine Anwendungsfunktion bereitstellen, um die Konfiguration erneut zu lesen, wenn Sie dazu aufgefordert werden, oder wir könnten einen komplizierteren Mechanismus bereitstellen, der feststellt, wenn sich die Konfigurationsdatei ändert ...

Langfristig können Sie feststellen, dass die Steuerprobleme mehr als nur einen Prozentsatz erfordern - zum Beispiel, dass die Steuergesetze eines Tages komplexer sind und mehrere Prozentsätze und einige Konstanten erfordern (z. B. der Betrag unter 10.000 USD, der mit X% besteuert wird, während die Rest besteuert mit Y%).

Dies legt im Wesentlichen die Verwendung eines Strategiemusters nahe, bei dem die hier fragliche Hauptklasse ein Strategieobjekt zur Berechnung der Steuer akzeptiert.

Die verschiedenen Strategien (sowie die Konstanten% und $) sollten aus der Konfigurationsdatei ausgewählt werden können. Zum Hinzufügen einer neuen Strategie muss nun neuer Code hinzugefügt werden, der vorhandene Code muss jedoch nicht unbedingt aktualisiert werden.

Jede Strategie kann möglicherweise ihre eigenen externen Konfigurationsargumente analysieren / interpretieren sowie die tatsächliche Steuer berechnen.

Dynamisch kann die Steuer außerdem vom maßgeblichen Gebietsschema abhängen, sodass das Gebietsschema möglicherweise mit dem Einkommen oder mit Mitarbeitern (oder beiden) verknüpft ist. In der externen Konfiguration können wir das Gebietsschema mit der Steuerstrategie verknüpfen.


Siehe auch Abhängigkeitsinjektion , wo wir diese Dinge explizit verwalten.


1
Die Frage war nicht, ob es eine schlechte Idee ist, so etwas wie einen Steuerprozentsatz im Code zu begraben. Ich bin sicher, dass dies für die meisten von uns hier (einschließlich des OP) offensichtlich ist. Die Frage war: "Verstößt dies gegen die OCP?" Ich verstehe also nicht, wie sich Ihre Antwort auf diese Frage bezieht.
Doc Brown

1

Wenn Sie die Klasse ändern müssen, um den Steuerwert zu ändern, verstößt ihr Design tatsächlich gegen OCP. Das geeignete Design für das, was Sie bisher beschrieben haben, besteht darin, dass die Rechnerklasse den Steuerwert als Parameter verwendet.

Wenn Ihre Klasse instanziiert ist (was bedeutet, dass es sich nicht um eine statische Klasse handelt), indem Sie die Steuervariablen-Klasseneigenschaft festlegen, deren Wert über den Konstruktor eingefügt wird, verbessern Sie auch den Klassenzusammenhalt.

Kurz gesagt, Ihr aktuelles Design lässt Ihre Klasse von einem konstanten Wert abhängen, der nicht wirklich eine Konstante ist (Konstante als Wert definieren, der sich niemals ändern würde, egal was passiert, wie der Wert von PI). Es verstößt gegen OCP. Ändern Sie das Design, um den Steuerwert als Konstruktorargument zu erhalten.


0

Stimmen Sie @Becuzz voll und ganz zu, und ich möchte dies nur zusammenfassen: Bei OCP geht es darum, wiederverwendete (daher nützliche) Abstraktionen zu finden, die in eine Klasse eingefügt werden. Das Verhalten der Klasse wird also nicht geändert, indem der Code geändert wird, sondern indem verschiedene Implementierungen bereitgestellt werden. Dies wird in Robert Martins Buch " Agile Softwareentwicklung, Prinzipien, Muster und Praktiken " kristallklar gemacht. Lesen Sie das entsprechende Kapitel "Das Open-Closed-Prinzip", "Abstraktion ist der Schlüssel", Unterkapitel. Es verdeutlicht ein weiteres Missverständnis, dass Verhalten nur durch Vererbung geändert werden kann. Es war Bertrand Meyer, der 1988 in seinem Buch „ Object Oriented Software Construction “ vorschlug , nicht Robert Martin.


-2

So wie ich es sehe, verstößt es nicht gegen das Open-Closed-Prinzip. Die Tatsache, dass sich etwas, das sich mit der Zeit ändern muss (z. B. der Steuerprozentsatz), als Konstante darstellt, ist jedoch ein Konstruktionsfehler: Sie sollten nicht den Wert der Konstante ändern, sondern wie Sie mit dem Steuerprozentsatz umgehen. Dies sollte eine Einstellung sein, die geändert werden kann, ohne das Ganze neu zu kompilieren.


Der "Designfehler" besteht darin, dass es gegen das Open-Closed-Prinzip verstößt, da Sie den Code neu kompilieren müssen, um die Konstante zu ändern.
Erdrik Ironrose
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.