Ich entwickle eine App, mit der Ventile in einer industriellen Umgebung geöffnet und geschlossen werden können, und habe mir etwas Einfaches überlegt:
public static void ValveController
{
public static void OpenValve(string valveName)
{
// Implementation to open the valve
}
public static void CloseValve(string valveName)
{
// Implementation to close the valve
}
}
(Die Implementierung würde einige Datenbytes an die serielle Schnittstelle schreiben, um das Ventil zu steuern - eine "Adresse", die vom Ventilnamen abgeleitet ist, und entweder eine "1" oder eine "0", um das Ventil zu öffnen oder zu schließen.)
Ein anderer Entwickler fragte, ob wir stattdessen eine separate Klasse für jedes physikalische Ventil erstellen sollten, von denen es Dutzende gibt. Ich bin damit einverstanden, dass es schöner wäre, Code zu schreiben PlasmaValve.Open()
als ValveController.OpenValve("plasma")
, aber ist das übertrieben?
Außerdem habe ich mich gefragt, wie ich das Design mit Blick auf einige hypothetische zukünftige Anforderungen am besten angehen kann:
- Wir werden gebeten, einen neuen Ventiltyp zu unterstützen, für dessen Öffnen und Schließen andere Werte erforderlich sind (nicht 0 und 1).
- Wir werden gebeten, ein Ventil zu unterstützen, das auf eine beliebige Position von 0-100 eingestellt werden kann, anstatt einfach "offen" oder "geschlossen" zu sein.
Normalerweise würde ich Vererbung für diese Art von Dingen verwenden, aber ich habe kürzlich angefangen, mich mit "Komposition über Vererbung" zu beschäftigen und mich zu fragen, ob es eine bessere Lösung gibt, wenn Komposition verwendet wird.
quelle
Antworten:
Wenn jede Instanz des Ventilobjekts den gleichen Code wie dieser ValveController ausführen würde, wären mehrere Instanzen einer einzelnen Klasse der richtige Weg. In diesem Fall konfigurieren Sie einfach im Konstruktor des Ventilobjekts, welches Ventil es steuert (und wie).
Wenn jedoch für jede Ventilsteuerung ein anderer Code zum Ausführen erforderlich ist und auf dem aktuellen ValveController eine riesige switch-Anweisung ausgeführt wird, die je nach Ventiltyp unterschiedliche Aktionen ausführt, wurde der Polymorphismus nur unzureichend implementiert. In diesem Fall schreiben Sie es in mehrere Klassen mit einer gemeinsamen Basis (falls dies sinnvoll ist) und lassen Sie das Prinzip der einzelnen Verantwortung Ihr Designleitfaden sein.
quelle
Mein Hauptproblem ist die Verwendung von Strings für den Parameter, der das Ventil identifiziert.
Erstellen Sie mindestens eine
Valve
Klasse, derengetAddress
Format den zugrunde liegenden Implementierungsanforderungen entspricht, und übergeben Sie diese anValveController
und stellen Sie sicher, dass Sie keine nicht vorhandenen Ventile erstellen können. Auf diese Weise müssen Sie bei der open- und close-Methode nicht mit falschen Zeichenfolgen umgehen.Ob Sie Convenience-Methoden erstellen, die das Öffnen und Schließen aufrufen,
ValveController
liegt bei Ihnen, aber um ehrlich zu sein, würde ich die gesamte Kommunikation zum seriellen Port (einschließlich der Codierung) in einer einzigen Klasse halten, die andere Klassen bei Bedarf aufrufen. Dies bedeutet, dass Sie bei der Migration auf einen neuen Controller nur eine Klasse ändern müssen.Wenn Sie gerne testen, sollten Sie auch
ValveController
einen Singleton erstellen, damit Sie ihn verspotten können (oder eine Trainingsmaschine für die Bediener erstellen).quelle