User Tools

Site Tools


patterns:inheritancerolestragegyoverview:inheritance

This is an old revision of the document!


Vererbung - Implementierung und Konsequenzen

Implementierung

  • UserAccount und SystemAccount werden beide von Account abgeleitet,
  • In Account gibt es einen abstrakten Konstruktor der in den Kindklassen implementiert werden muss. Das Systemkonto wird z.B. eine Beschreibung erhalten1), und das Personenkonto eine PersonID,
  • Es gibt das abstrakte Ereignis AccountCreated, welches nur die ID des Kontos beinhaltet. UserAccount wird im Konstruktor das UserAccountCreated:AccountCreated Ereignis melden, welches neben der ID des Kontos die PersonID beinhalten wird. Entsprechendes gilt für SystemAccount oder neue Kontenarten,
  • Auf der Befehlsseite wird es den abstrakten Befehl CreateAccount geben. Für UserAccount wird es CreateUserAccount:CreateAccount geben, entsprechendes gilt für SystemAccount,
  • Im Command Handler wird Service Locator verwendet, um die korrekte Factory für die entsprechenden Implementierungen von CreateAccount zu ermitteln,
  • Die Projektionsseite ist nun tatsächlich ein wenig komplexer. Projektionen werden dadurch erzeugt, dass Ereignisse behandelt werden, und aus diesen Ereignissen Sichten erstellt werden, die abgefragt werden. Die Sichten werden dann in Data Transfer Objects2) gewandelt, die dann an andere Systeme3) gesendet werden können. Die anderen Systeme müssen nun mit den DTOs arbeiten können. Die Komplikation liegt darin, dass jede neue Kontoart neue Ereignisse, DTOs und Anforderungen and die Sichten einführt. Das wird am besten hier besprochen:

Konsequenzen

Ich4) bin an der Erstellung von Konten interessiert, will wissen, wann ein Konto erstellt wird. Ich abonniere somit das AccountCreated Ereignis. Da UserAccountCreated und SystemAccountCreated von AccountCreated abgeleitet sind, würden beide von mir behandelt werden. Wenn eine neue Kontoart mit einem neuen Erzeugungsereignis dazu kommt, wird mir das auch automatisch zum Behandeln übergeben.

In diesem Fall sollte ich nicht fest auf die vorhandenen [User/Sytem]AccountCreated reagieren, sondern auf die Basisklasse AccountCreated. Ansonsten würde ich Ereignisse eines neu dazu gekommenen Kontos nicht behandeln, und die Systemerweiterbarkeit ist nicht gegeben. Angenommen, ich möchte eine Liste aller Konten darstellen, mit der Bezeichnung der Kontoart und der Kontobezeichnung. Für Systemkonten ist das “Systemkonto”5) plus die Bezeichnung des Kontos, z.B. “Outlook-Schnittstellenkonto”, für Personenkonten “Benutzerkonto” samt der Personenbezeichnung. Das ist schon nicht ganz so einfach, weil die Kontoart in die Sprache des Anwenders übersetzt werden sollte, und weil UserAccount nur die PersonID hält, nicht aber die Personenbezeichnung kennt. Und was, wenn neue Kontenarten dazu kommen?

Wir haben somit identifiziert, welche Gemeinsamkeiten die unterschiedlichen Kontoarten besitzen sollen. Die Bezeichnung der Kontoart plus die Bezeichnung des Kontoinhabers. Welche Ereignisse führen nun dazu, dass sich die Bezeichnung des Kontoinhabers ändert? SystemAccountDescriptionChanged wäre eins. Was ist mit der Personenbezeichnung? Die Person eines UserAccounts ändert sich nie, aber die Bezeichnung kann sich ändern, entweder weil sie korrigiert wurde, oder weil die Person ihren Namen geändert hat6). Muss ich also wissen, dass ich auch auf PersonNameChanged Ereignisse lauschen muss? Das ginge ja noch, aber bei neuen Konten wäre das nicht mehr möglich.

Die Lösung7): Zusammenfassende Ereignisse für Projektionen von abstrakten Klassen. Als erstes muss identifiziert werden, welche Gemeinsamkeiten für abstrakte Klassen existieren. Dann werden Ereignisse eingeführt, die Änderungen an diesen Gemeinsamkeiten melden. Diese Ereignisse werden ausgelöst durch

  • andere Ereignisse. Z.B. wird ein handler von PersonNameChanged eingebaut, der den neuen Namen meldet. Dieser handler behandelt ebenfalls UserAccountCreated, um zu wissen, zu welchem Benutzerkonto die Person gehört. Beim behandeln von PersonNameChanged wird also der neue Personenname gespeichert, das Konto8) der Person werden ermittelt, und für jedes wird ein AccountDescriptionChanged(Guid AccountID, string Description) Ereignis ausgelöst. Keine Ahnung wie dieses Muster heißt, es ist aber einfach zu verstehen und genauso einfach zu implementieren,
  • regelmäßige Abfragen. Wenn Namensänderungen z.B. nicht über Ereignisse gemeldet werden, würde man die Personenbezeichnungen regelmäßig abfragen. Wenn sich eine ändert, wird wie im ersten Fall dafür ein AccountDescriptionChanged Ereignis ausgelöst.
  • DAS GEHT NICHT: Datenbanksichten. Man könnte versuchen, eine Query zu bauen, die für alle Kontoarten um ein UNION SELECT erweitert wird. Das ist aber eine sehr starkte Koppelung.

Es können beliebig tiefe Ereignisketten gebildet werden. AccountDescriptionChanged könnte z.B. von einem weitern handler in ein weiteres Ereignis gewandelt werden, usw.

Die Kontoartbezeichnung sollte einen Default haben, z.B. in Deutsch. Jedes DTO für Account wird zudem den Typ beinhalten, also z.B. PROM.Authentication.UserAccount. Anhand dieses Typs kann nun überall über Service Locator entsprechend mit dem Konto umgegangen werden. Das UI kann zum Bearbeiten den entsprechenden Controller laden, ebenso kann ein Übersetzer gefunden werden, der aus der Typenbezeichnung eine Bezeichnung in der Sprache des angemeldeten Users macht.

1) z.B. “Outlook-Schnittstellenkonto”
2) DTO
3) vorwiegend an das UI
4) ein Event Handler
5) wenn die Liste in Deutsch dargestellt werden soll
6) z.B. durch Heirat
7) merkwürdig, darüber habe ich noch nirgendwo was lesen können, wobei die Lösung doch so einfach ist
8) bzw. die Konten
patterns/inheritancerolestragegyoverview/inheritance.1357569746.txt.gz · Last modified: 2013/01/07 15:42 by rtavassoli