2010-05-18 12 views
67

Próbuję zrozumieć Anemiczne Modele Domeny i dlaczego są one rzekomo anty-wzorem.Unikanie anemicznego modelu domeny - prawdziwy przykład

Oto przykład z prawdziwego świata.

Mam klasy pracownika, który ma mnóstwo właściwości - nazwa, płeć, nazwa użytkownika, itp

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

Następnie mamy system, który obejmuje obracanie przychodzących połączeń telefonicznych i zapytań stronie internetowej (znane jako „potencjalnych ") równomiernie wśród sprzedawców. Ten system jest dość złożony, ponieważ obejmuje zapytania o zaokrąglanie robót, sprawdzanie świąt, preferencji pracowników itp. Tak więc ten system jest obecnie podzielony na usługę: 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 
    } 
} 

Następnie na tylnej stronie naszego formularza zapytania mamy kodu:

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

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

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

Naprawdę nie napotkać wiele problemów z tym podejściem, ale podobno jest to coś, co powinno uruchomić krzycząc, ponieważ jest to model domeny anemicznej Anemic Domain Model.

Ale dla mnie nie jest jasne, gdzie powinna iść logika w usłudze obrotu ołowiu. Czy powinien pójść na czele? Czy powinien iść do pracownika?

Co ze wszystkimi wstrzykniętymi repozytoriami itp., Których wymaga usługa rotacji - w jaki sposób zostałyby one wstrzyknięte pracownikowi, zważywszy, że przez większość czasu w kontaktach z pracownikiem nie potrzebujemy żadnego z tych repozytoriów?

+0

+1 świetne pytanie! – mdma

+0

Więc jak wygląda "ILead", jeśli nie jest oczywiste, aby umieścić w nim .SelectEmployee()? –

+0

Cóż, główną przyczyną w tym przypadku jest zapytanie w sieci, więc będzie mieć właściwość Komentarze itp. Ale mamy również zapytania telefoniczne, aplikacje, cytaty itp., Które są nieco inne. Interfejs ILead miałby właściwości takie jak LocationOfLead, TimeOfLead itp. – cbp

Odpowiedz

49

W tym przypadku nie stanowi to Anemicznego Modelu Domeny. Anemiczny model domeny to specifically about validating and transforming the objects. Przykładem może być sytuacja, w której zewnętrzna funkcja faktycznie zmieniła stan Pracowników lub zaktualizowała ich szczegóły.

Co się dzieje w tym przypadku, to bierzesz wszystkich pracowników i wybierasz jedną z nich na podstawie ich informacji. Dobrze jest mieć oddzielny obiekt, który bada innych i podejmuje decyzje w odniesieniu do tego, co znajduje. NIE jest dobrze mieć obiekt, który jest używany do przenoszenia obiektu z jednego stanu do drugiego.

Przykładem anemiczne Domain model w Twoim przypadku byłoby mieć metodę numer zewnętrzny

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

że przyjmuje obiekt pracownika i aktualizuje swoją przepracowanych godzin na tydzień, upewniając się, że flagi są podniesione, jeśli godziny przekraczają określony limit. Problem polega na tym, że jeśli masz tylko obiekty pracownicze, nie masz wiedzy o tym, jak modyfikować godziny w ramach poprawnych ograniczeń.W takim przypadku sposobem radzenia sobie z tym byłoby przeniesienie metody updateHours do klasy Employee. To jest sedno anty-wzorcowego modelu Anemicznej Domeny.

+0

Ale co, jeśli pracownik jest trwałym obiektem dla bazy danych. Dlaczego powinienem tam umieścić metodę? To samo pytanie dotyczy DTO, w którym nie umieszczasz żadnych metod. Gdzie wtedy umieścić metodę updateHours? – Pascal

+0

'updateHours' należy do klasy Employee. Powinieneś przekazać mu wszelkie dane niezbędne do aktualizacji godzin, na przykład zadanie, które zostało zakończone. Obiekty współpracowników też są w porządku, ale najlepiej brak usług. – MauganRa

29

Myślę, że twój projekt jest w porządku tutaj. Jak wiecie, anemiczny model anty-wzorcowy jest przeciwieństwem trendu unikania jakiegokolwiek zachowania zakodowanego w obiektach domenowych. Ale odwrotnie, nie oznacza to, że zachowanie obiektu domeny musi być enkapsulowane przez ten obiekt.

Zgodnie z ogólną zasadą zachowania, które są nierozerwalnie związane z obiektem domeny i są zdefiniowane w całości w kontekście tej jednej instancji obiektu domeny, mogą być zawarte w obiekcie domeny. W przeciwnym razie, aby utrzymać odpowiedzialność jasno, najlepiej jest umieścić ją zewnętrznie w firmie współpracującej/usłudze, tak jak zrobiłeś.

+5

dokładnie. Jest to prawdziwy moduł zewnętrzny (LeadQueueManager lub coś podobnego) z dużą ilością wewnętrznej logiki - to absolutnie nie jest anemiczny model domeny. Co pracownik wie o harmonogramie kolejki połączeń? Nic;) – TomTom

13

Wszystko spoczywa w twojej głowie - pomyśl, aby obrót był częścią modelu domeny i problem się rozwiązuje.

Rotacja wymaga przechowywania informacji o wielu pracownikach, więc nie należy do ołowiu ani do pojedynczego obiektu pracowniczego. To zasługuje na bycie obiektem domeny samo w sobie.

Po prostu zmiana nazwy "RotationService" na coś takiego jak "Organization.UserSupportDepartment" czyni to oczywistym.

0

Jeśli twój model domeny zawiera tylko role i rzeczy, a nie działania jako zachowanie, to jest anemiczny. Jednak mówię o zachowaniu w odniesieniu do obiektu model, a nie obiektu. Rozmawiam z różnicy między nimi w innej odpowiedzi ... https://stackoverflow.com/a/31780937/116442

Od pytania, złamiesz moje pierwsze zasady modelowania analiza dwóch domen: -

  1. Zachowanie modelowany jako (zarejestrowanych) prowadzone są w sercu modelu domeny. Najpierw dodaj je.
  2. Aktywność domeny modelu jako klas, a nie metody.

Dodałabym aktywność "Zapytanie" do modelu. Dzięki temu model zachowuje się i może łączyć się i pracować jako grupa obiektów bez zewnętrznego kontrolera lub skryptu.

EnquiryHandlerModel

Powiązane problemy