Welches API-Design zum Speichern generischer Daten in einem spezifischeren Format?


8

In dem Projekt, an dem ich arbeite, senden wir Nachrichten über Widgets über Nachrichtenwarteschlangen und serialisieren sie als XML in die Warteschlangen. Das XML-Schema enthält Tags für Eigenschaften, die allen Typen dieser Widgetnachrichten gemeinsam sind, z. B. Widgettyp, Befehlsname und Ziel. Es kann auch eine beliebig große Liste von Schlüssel-Wert-Paaren enthalten, um die Speicherung von Eigenschaften zu ermöglichen, die nur für einen bestimmten Typ von Widget-Nachrichten relevant sind. Die WidgetMessageKlasse kapselt diese Daten und die Klassen WidgetMessageXmlWriterund WidgetMessageXmlReaderbieten eine Serialisierung zu und von XML.

Ich habe einige Klassen erstellt, die bestimmte Nachrichten kapseln, z. B. ein FooPlaySoundMessageWidget für "Foo" oder ein Widget BarSetLightPatternMessagefür "Bar". Sie verfügen jeweils über eine ToWidgetMessageInstanzmethode und eine FromWidgetMessagestatische Methode zum Konvertieren in und aus der WidgetMessageKlasse. Jede Nachrichtenfamilie erbt von einer abstrakten Klasse für diesen Widget-Typ, z. B. FooMessageund BarMessage, die wiederum von der WidgetMessageMappingKlasse erbt . Hier werden die allgemeinen Nachrichteneigenschaften und die geschützten Methoden gespeichert, die von Unterklassen für die Konvertierung verwendet werden. Keine dieser Klassen erbt von, WidgetMessageda ich nicht möchte, dass sie die Schlüsselwertsammlungseigenschaft und die zugehörigen Methoden erben , weshalb eher eine Konvertierung als ein einfaches Casting erforderlich ist.

Ich mag die Einfachheit meiner API (z. B. FooPlaySoundMessage msg = FooPlaySoundMessage.fromWidgetMessage(widgetMessage)), aber die Tatsache, dass ich geschützte Methoden in einer Basisklasse verwenden muss, um Funktionen gemeinsam zu nutzen, und statische Methoden, um sie verfügbar zu machen, lässt mich fragen, ob es eine oder zwei separate Klassen geben sollte hier (ähnlich WidgetMessageXmlWriterund WidgetMessageXmlReader). Andererseits dachte ich, dass ein Teil des Punktes von OOP darin besteht, Daten und Methoden zu gruppieren und so "dumme Datenobjekte" zu vermeiden .

Habe ich also die richtige Idee, indem ich meinen Datenobjekten Konvertierungsmethoden hinzufüge, oder sollte diese Funktionalität in eine andere Klasse extrahiert werden?

Aktualisieren:

Ich denke, dass ich in allen Details meines aktuellen Entwurfsversuchs das Problem, das ich zu lösen versuche, nicht klar genug erklärt habe.

Zusammenfassend habe ich eine "generische" DTO-Klasse mit einigen stark typisierten Eigenschaften und einer Sammlung von Schlüssel-Wert-Paaren zum Speichern anderer benutzerdefinierter Daten. Ich möchte einige spezialisierte DTO-Klassen für jeden Satz von benutzerdefinierten Daten haben, die dieselben Daten wie das generische DTO speichern, außer dass die Schlüssel-Wert-Paare durch stark typisierte Eigenschaften ersetzt werden. Was ist das beste Design für die Konvertierung zwischen diesen beiden DTO-Typen?


Klingt nach Dekorationsmuster? - en.wikipedia.org/wiki/Decorator_pattern
Stevo

Zweitens das. Ich denke dir geht es gut.
Stu

1
Nebenbei bemerkt: Wenn es für Sie funktioniert, ist es in.
Stu

Was macht die Nachricht, anstatt nur die Nachricht zu sein?
Piotr Gwiazda

Die alleinige Verantwortung dieser Klassen besteht darin, in und aus der WidgetMessage-Klasse konvertiert zu werden. Es gibt ein 'Widget Comms'-Projekt, das WidgetMessages verwendet und mit den Widgets kommuniziert. Ich habe diesen WidgetMessageMapping-Klassen keine solche Kommunikationsfunktionalität hinzugefügt, da nur das Widget Comms-Projekt wissen sollte, wie man mit den Widgets kommuniziert, während die Nachrichten in verschiedenen Teilen der Anwendung erstellt werden können. Die WidgetMessageMappings dienen lediglich dazu, zu vermeiden, dass Nachrichtenanalyse- und Erstellungscode über die Ebenen der Anwendung verteilt wird.
Robert Johnson

Antworten:


1

Wenn FooPlaySoundMessage weiß, wie man Sound spielt und wie man sich einem Nachrichtenwarteschlangenformat zuordnet, kann man sagen, dass die Klasse mehr als eine Verantwortung hat. Wenn der eigentliche Sound direkt an eine andere Klasse delegiert wird, ist Ihre FooPlaySoundMessage im Grunde ein Datenübertragungsobjekt. In diesem Fall scheint es mir in Ordnung zu sein, allgemeine Zuordnungen in eine gemeinsam genutzte Basisklasse einzufügen.

Ich würde es wahrscheinlich aber trennen. Datenübertragungsobjekte haben normalerweise wenig bis gar keinen Code. Sie können FooPlaySoundMessage als einen sehen.

Irgendwann müssen Sie möglicherweise dieselben Daten auf andere Weise oder in einem anderen Format übertragen (json vielleicht?). Sie könnten es für jetzt YAGNI und dann trennen.

Ich würde wahrscheinlich eine Message-Handler-Klasse erstellen, die die allgemeinen Teile analysiert, den Nachrichtentyp erkennt und dann an einen bestimmten Parser delegiert, z. B. FooPlaySoundXmlMessageParser. Wenn Sie Zweifel haben, bevorzugen Sie die Komposition gegenüber der Vererbung.


Es wird nur die WidgetMessage in und aus XML konvertiert - die spezialisierten DTOs werden immer nur in und aus WidgetMessages konvertiert. In meinem aktuellen Design werden sie immer noch als "Nachrichten" bezeichnet, obwohl nur die WidgetMessage in eine Warteschlange gestellt wird, damit ich Ihre Verwirrung verstehen kann. Ich habe meine Frage aktualisiert, um das Problem, das ich zu lösen versuche, besser zu erklären.
Robert Johnson
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.