Gelegentlich kann beim Schreiben von Code eine bedingte Verzweigung multipliziert (kombiniert) auftreten. Zum Beispiel
etc.
In diesem Artikel geht es darum, wie Sie Änderungen standhalten können, ohne die Sichtbarkeit in diesen Situationen zu beeinträchtigen. Das Codebeispiel wird in Python gezeigt, aber die Idee ist nicht auf die Programmiersprache beschränkt. Wenn die Implementierung eine objektorientierte Sprache ist, kann dieselbe Implementierung erreicht werden.
Hier möchte ich als Beispiel die Filmpreise betrachten. Zum Beispiel gibt es allgemeine Erwachsene, Studenten und Senioren als Käufer, und der Preis ändert sich je nach Tageszeit (tagsüber, späte Show).
Während des Tages | Späte Show | |
---|---|---|
Allgemeines | 1800 Yen | 1300 Yen |
Schüler | 1.500 Yen | 1.500 Yen |
Senior | 1100 Yen | 1100 Yen |
Angenommen, es gibt eine Abzinsungsregel für den Standardsatz (1800 Yen), und die Anwendung dieser Regel wird im Code ausgedrückt.
Abzinsungsregel vom Standardbetrag
Wochentags | Wochentage (späte Show) | |
---|---|---|
Allgemeines | +-0 Yen | -500 Yen |
Schüler | - | -500 Yen |
Senior | -700 Yen | -700 Yen |
In einem solchen Fall ist es wie folgt schmerzhaft, wenn Sie einfach mit prozeduraler bedingter Verzweigung schreiben.
from datetime import datetime
import enum
#Viewer-Klassifizierung
class ViewerType(enum.Enum):
ADULT = "adult"
STUDENT = "student"
SENIOR = "senior"
#Geben Sie die Sendegebühr basierend auf der Zuschauerklassifizierung, der Filmstartzeit und der Standardgebühr zurück
def charge(viewer_type: ViewerType, movie_start_at: datetime base_charge: int) -> int:
#Späte Show nach 20:00 Uhr
if movie_start_at.hour < 20:
if viewer_type == ViewerType.ADULT:
return base_charge
elif viewer_type == ViewerType.STUDENT:
return base_charge - 300
else:
return base_charge - 700
if viewer_type == ViewerType.ADULT or viewer_type == ViewerType.STUDENT:
return base_charge - 500
else:
return base_charge - 700
Selbst wenn Sie es auf einen Blick betrachten, sind die allgemeinen Aussichten schlecht, und ich denke, es ist schwierig zu sagen, ob es richtig umgesetzt wird. Wenn sich die Arten von Käufern wie registrierten Mitgliedern erhöhen oder sich die Regeln für vorrangige Gebühren ändern, ist es auch schwierig zu wissen, wo die Verarbeitung hinzugefügt werden muss.
In einem solchen Fall können Sie eine bessere Ansicht erhalten, indem Sie ** das Ereignis (Daten, die die Quelle der bedingten Verzweigung darstellen) ** berücksichtigen, das sich auf den Prozess auswirkt, den Sie als ** Kontext ** ausführen möchten.
In diesem Fall wird die ** Startzeit der Show **, die das Kriterium dafür ist, ob es sich um eine späte Show handelt, im Code als Kontext ** für die Bestimmung des endgültigen ** Preises ausgedrückt.
from datetime import datetime
import dataclasses
@dataclasses.dataclass
class MovieStartAtContext:
movie_start_at: datetime
def is_late_show(self) -> bool:
return self.movie_start_at.hour >= 20
Vorläufig konnte ich den Kontext ** ausdrücken, ob die Startzeit der Show eine späte Show ist **, aber es macht keinen Sinn, dies in den obigen Verfahrenscode zu erweitern.
from datetime import datetime
import dataclasses
@dataclasses.dataclass
class MovieStartAtContext:
movie_start_at: datetime
def is_late_show(self) -> bool:
return self.movie_start_at.hour >= 20
#Preisberechnung durch den Betrachter
#
#Die vom Betrachter aufgerufene Methode ändert sich je nachdem, ob es sich um eine späte Show handelt oder nicht.
#
# -Für späte Shows: late_show_charge()
# -Während des Tages: normal_charge()
def charge_for(self, viewer: Viewer, base_charge: int) -> int:
if self.is_late_show():
return viewer.late_show_charge(base_charge)
return viewer.normal_charge(base_charge)
Auf diese Weise ist es ausreichend, die Berechnungsmethoden für die verspätete Show und die reguläre Gebühr für jeden Zuschauertyp zu definieren (es liegt in der Verantwortung der Kontextzeit der Showzeit, die entsprechende Methode aufzurufen).
Die Implementierung der Gebührenberechnung für jeden Betrachter ist wie folgt.
class Viewer:
def normal_charge(self, base_charge: int) -> int:
pass
def late_show_charge(self, base_charge: int) -> int:
pass
class AdultViewer(Viewer):
def normal_charge(self, base_charge: int) -> int:
return base_charge
def late_show_charge(self, base_charge: int) -> int:
return base_charge - 500
class StudentViewer(Viewer):
def normal_charge(self, base_charge: int) -> int:
return base_charge - 300
def late_show_charge(self, base_charge: int) -> int:
return base_charge - 500
class SeniorViewer(Viewer):
def normal_charge(self, base_charge: int) -> int:
return base_charge - 700
def late_show_charge(self, base_charge: int) -> int:
return base_charge - 700
Sie können sehen, dass die Abzinsungsregel-Regeltabelle im Code fast so ausgedrückt wird, wie sie ist.
Abzinsungsregel vom Standardbetrag
Wochentags | Wochentage (späte Show) | |
---|---|---|
Allgemeines | +-0 Yen | -500 Yen |
Schüler | -300 Yen | -500 Yen |
Senior | -700 Yen | -700 Yen |
Wenn Sie den bisher definierten Code integrieren, sieht Ihre ursprüngliche Funktion "load ()" folgendermaßen aus:
class ViewerFactory:
viewer_mapping = {
ViewerType.ADULT: AdultViewer(),
ViewerType.STUDENT: StudentViewer(),
ViewerType.SENIOR: SeniorViewer()
}
@classmethod
def create(cls, viewer_type: ViewerType) -> Viewer:
return cls.viewer_mapping[viewer_type]
def charge(viewer_type: ViewerType, movie_start_at: datetime, base_charge: int) -> int:
context = MovieStartAtContext(movie_start_at)
viewer = ViewerFactory.create(viewer_type)
return context.charge_for(viewer, base_charge)
Auf diese Weise können Sie eine neue Viewer-Klasse definieren, wenn sich der im Beispiel erwähnte Typ des Mitgliedsregistranten erhöht, und selbst wenn sich eine neue Gebührenkategorie wie die Urlaubsgebühr erhöht. Ich denke, dass Sie es implementieren können, ohne sich am Montageort zu verlaufen.
Wenn bedingte Verzweigung multiplikativ (kombinatorisch) auftritt
Hoffentlich können Sie Ihren Code sauberer und einfacher erweitern. Ich hoffe, es wird für die Implementierung hilfreich sein.