it-swarm.com.de

Vermeidung anämischer Domänenmodelle - ein echtes Beispiel

Ich versuche, anämische Domänenmodelle zu verstehen und warum sie angeblich ein Anti-Muster sind.

Hier ist ein reales Beispiel.

Ich habe eine Angestelltenklasse, die eine Menge Eigenschaften hat - Name, Geschlecht, Benutzername usw

public class Employee
{
    public string Name { get; set; }
    public string Gender { get; set; }
    public string Username { get; set; }
    // Etc.. mostly getters and setters
}

Als nächstes haben wir ein System, bei dem eingehende Telefonanrufe und Website-Anfragen (bekannt als "Leads") gleichmäßig zwischen den Vertriebsmitarbeitern ausgetauscht werden. Dieses System ist recht komplex, da es sich um ein Round-Robin-Verfahren handelt, bei dem nach Feiertagen, Mitarbeiterpräferenzen usw. gesucht wird. Daher ist dieses System derzeit in einen Dienst unterteilt: EmployeeLeadRotationService.

public class EmployeeLeadRotationService : IEmployeeLeadRotationService
{
     private IEmployeeRepository _employeeRepository;
     // ...plus lots of other injected repositories and services

     public void SelectEmployee(ILead lead)
     {
         // Etc. lots of complex logic
     }
}

Dann haben wir auf der Rückseite unseres Website-Anfrageformulars folgenden Code:

public void SubmitForm()
{
    var lead = CreateLeadFromFormInput();

    var selectedEmployee = Kernel.Get<IEmployeeLeadRotationService>()
                                 .SelectEmployee(lead);

    Response.Write(employee.Name + " will handle your enquiry. Thanks.");
}

Ich habe nicht wirklich viele Probleme mit diesem Ansatz, aber angeblich ist dies etwas, vor dem ich schreien sollte, weil es ein anämisches Domänenmodell ist.

Aber für mich ist nicht klar, wohin die Logik im Lead Rotation Service gehen soll. Sollte es in Führung gehen? Sollte es in den Mitarbeiter gehen?

Was ist mit all den injizierten Repositorys usw., die der Rotationsservice benötigt - wie würden sie dem Mitarbeiter injiziert, da wir im Umgang mit einem Mitarbeiter die meiste Zeit keine dieser Repositorys benötigen?

71
cbp

In diesem Fall handelt es sich nicht um ein anämisches Domänenmodell. Bei einem anämischen Domänenmodell geht es insbesondere um die Validierung und Transformation der Objekte . Ein Beispiel hierfür wäre, wenn eine externe Funktion den Status der Mitarbeiter tatsächlich ändert oder deren Details aktualisiert.

in diesem Fall nehmen Sie alle Mitarbeiter mit und treffen anhand ihrer Informationen eine Auswahl. Es ist in Ordnung, ein separates Objekt zu haben, das andere untersucht und Entscheidungen darüber trifft, was es findet. Es ist NICHT in Ordnung, ein Objekt zu haben, mit dem ein Objekt von einem Zustand in einen anderen überführt wird.

Ein Beispiel für ein anämisches Domänenmodell in Ihrem Fall wäre eine externe Methode

updateHours(Employee emp) // updates the working hours for the employee

das nimmt ein Employee-Objekt und aktualisiert seine Arbeitsstunden für die Woche, wobei sichergestellt wird, dass Flags gesetzt sind, wenn die Stunden eine bestimmte Grenze überschreiten. Das Problem dabei ist, dass Sie, wenn Sie nur Mitarbeiterobjekte haben, nicht wissen, wie Sie ihre Stunden innerhalb der richtigen Einschränkungen ändern können. In diesem Fall müssen Sie die updateHours-Methode in die Employee-Klasse verschieben. Das ist der Kern des Antimusters des anämischen Domänenmodells.

52
radman

Ich denke, Ihr Design ist hier in Ordnung. Wie Sie wissen, ist das Antimuster des anämischen Domänenmodells eine Gegenreaktion gegen den Trend, in Domänenobjekten codiertes Verhalten zu vermeiden. Umgekehrt bedeutet dies jedoch nicht, dass das alles - Verhalten, das sich auf ein Domänenobjekt bezieht, von diesem Objekt gekapselt werden muss.

Als Faustregel gilt, dass Verhalten, das eng mit dem Domänenobjekt verbunden ist und vollständig in Bezug auf diese eine Domänenobjektinstanz definiert ist, in das Domänenobjekt aufgenommen werden kann. Andernfalls ist es zur Klärung der Verantwortlichkeiten am besten, diese extern an einen Mitarbeiter/Service zu übertragen, wie Sie es getan haben.

29
mdma

Es ist alles in Ihrem Kopf - betrachten Sie Rotationsservice als Teil des Domain-Modells und das Problem löst sich.

Rotation muss Informationen über viele Mitarbeiter speichern, sodass sie weder zu einem Lead noch zu einem einzelnen Mitarbeiterobjekt gehören. Es ist zu verdienen, ein Domain-Objekt an sich zu sein.

Das Umbenennen von "RotationService" in "Organization.UserSupportDepartment" macht es offensichtlich.

14
ima

Wenn Ihr Domain-Modell nur Rollen und Dinge enthält, keine Aktivitäten als Verhalten, ist es anämisch. Ich spreche jedoch von Verhalten in Bezug auf ein Modell kein Objekt . Ich spreche über den Unterschied zwischen ihnen in einer anderen Antwort ... https://stackoverflow.com/a/31780937/116442

Aufgrund Ihrer Frage brechen Sie meine ersten beiden Modellierungsregeln für die Domänenanalyse:

  1. Als (aufgezeichnetes) Verhalten modelliertes Verhalten Aktivitäten sind das Herzstück eines Domänenmodells. Fügen Sie sie zuerst hinzu.
  2. Modellieren Sie Domänenaktivitäten als Klassen, nicht als Methoden.

Ich würde dem Modell eine Aktivität "Anfrage" hinzufügen. Damit verfügt das Modell über Verhalten und kann als Gruppe von Objekten ohne einen externen Controller oder ein Skript kombiniert und bearbeitet werden.

 EnquiryHandlerModel

0
aryeh