Statyczna zależność w modelu

Odpowiedz Nowy wątek
2019-03-05 11:12
0

Hej, mam problem, z którym się bawię jak dziecko. Już drugi dzień zastanawiam się jak rozwiązać dość prostą kwestię.

Mam jakiś model. Dajmy na to, że jest Dokument, który składa się z różnych elementów.
Każdy element dokumentu jest tworzony za pomocą Buildera.
Do tej pory miałem tak, że Builder był osobnym serwisem, do którego wstrzykiwałem zależność odpowiadającą za tłumaczenia tekstów:

public class ModelBuilder
{
  ILocalizer localizer;
  public ModelBuilder(ILocalizer loc)
  {
    localizer = loc;
  }

  public SomeItem CreateSomeItem()
  {
    SomeItem item = new SomeItem();
    item.Name = localizer.Localize["Blabla"];
    //dalsze tworzenie elementu
  }
}

Ale w pewnym momencie okazało się, że w pewnych warunkach zamiast jednego SomeItem powinienem utworzyć jeszcze inny obiekt i je ze sobą powiązać. I tu zaczął się problem. Rozwiązania miałem dwa:

  1. Umieścić tą logikę biznesową w serwisie (odpowiedzialnym za komunikację z bazą danych), np:
public class SomeItemService
{
    IOtherItemService otherService;

   public void AddSomeItem(SomeItem item)
   {
      if(jakis_warunek)
      {
          OtherItem oi = CreateOtherItem(); //odwołanie do buildera
          otherService.Add(oi);
          item.Parent = oi;
      }

     db.Save(item);
   }

Ale trochę mi to nie do końca pasuje. Głównie z tego powodu, że ciężko będzie to pożenić z UI.
Z drugiej strony przyszło umieszczenie tej logiki w modelu. I tu niby wszystko by się zgodziło, ale problemem dla mnie stała się zależność od ILocalizer. Zapaliła mi się taka lampka, że chyba nie powinienem tego robić. A pomysł jest taki, że całego buildera przenoszę do modelu, np:

public class Document
{
    public static ILocalizer Localizer {get; set;}

    public SomeItem CreateSomeItem()
    {
        SomeItem item = new SomeItem();
        item.Name = Localizer["Blabla"];
        if(jakis_warunek)
        {
            OtherItem oi = new OtherItem();
            item.Parent = oi;
        }

       Items.Add(someItem);
    }
}

Tu wszystko mi wygląda ok, poza tym Localizerem. Bardzo on mnie tu dźga w bok i nie wiem za bardzo, co z tym zrobić. Localizer będzie oczywiście rejestrowany jako singleton. Document nie, bo w aplikacji może być kilka różnych dokumentów.

Co Wy o tym myślicie? A może jest jakieś inne rozwiązanie?

Pozostało 580 znaków

2019-03-05 11:59
0

Statyczny Localizer to ZUO.
Może coś takiego?

class DocumentFactory {
    private final SimpleItemFactory simpleItemFactory;
    private final CompositeItemFactory compositeItemFactory;

    Document build() {
        Document document = new Document();
        Item item1 = simpleItemFactory.build(item1Parameters);
        Item item2 = simpleItemFactory.build(item2Parameters);
        Item item3 = compositeItemFactory.build(item3Parameters, item2);
        document.addAll(item1, item3);
        //...
        return document;
    }
}

class SimpleItemFactory {
    private final ILocalizer localizer;

    Item build(ItemParameters itemParameters) {
        Item item = new Item();
        localize(item, itemParameters.language);
        //...
        return item;
    }
}

class CompositeItemFactory {
    private final ILocalizer localizer;

    Item build(ItemParameters itemParameters, Item child) {
        Item item = new Item();
        localize(item, itemParameters.language);
        child.setParent(child);
        item.setChild(child);
        //...
        return item;
    }
}
edytowany 1x, ostatnio: Tyvrel, 2019-03-05 12:05

Pozostało 580 znaków

2019-03-05 12:28
0

No właśnie nie jest to takie proste, bo takie było moje pierwsze podejście. Tu trochę chodzi o to, że builder w pewnych momentach musi budować coś więcej niż to, co by wynikało z kodu. Nie wiem, czy nie naruszam tu SRP.

Pozostało 580 znaków

2019-03-05 13:13
0

Ten Twój builder nie powinien być na tyle głupi, żeby budować tylko to co mu się powie? I tu masz pewnie 2 przypadki: czasem ktoś mówi, że trzeba zbudować coś więcej, a czasem ten sam ktoś (albo ktoś inny) nie wspomina builderowi, że ma budować coś więcej.

Innymi słowy logika co budować nie powinna być wg mnie w builderze, tylko u tego kto z buildera korzysta.

edytowany 1x, ostatnio: yarel, 2019-03-05 13:13

Pozostało 580 znaków

2019-03-05 13:23
0

@Juhas
To wyjaśnij o co chodzi. Co to znaczy, że fabryka ci buduje więcej niż by to wynikało z kodu

Pozostało 580 znaków

2019-03-05 22:01
0

Mam jakby dwie klasy jakiś okresów, np:

class Period
{
    public DateTime StartDate {get;set;}
    public DateTime EndDate {get;set;}
    public IList<Sheet> Sheets {get;set;}
}

class Sheet: Period
{
  public Period ParentPeriod {get;set;}
  //jakieś dodatkowe elementy
}

I teraz chodzi o tworzenie Sheet. Załóżmy, że klasa Period może mieć maksymalnie 12 Sheetów w sobie, w taki sposób:

Period1
     Sheet1
     Sheet2
     ...
     Sheet12

Period2
    Sheet1

I teraz próbuję zrobić coś, co w prosty sposób utworzy odpowiedni Sheet. I tu mamy 3 przypadki:

  1. Period, do którego ma należeć Sheet nie istnieje. Dlatego poza Sheetem musimy stworzyć jeszcze Period.
  2. Period, do którego ma należeć Sheet istnieje i ma mniej niż 12 elementów. Tu nie ma problemu, po prostu tworzymy zwykłego Sheeta i dodajemy go do Period.
  3. Period, do którego ma należeć Sheet istnieje, ale ma 12 elementów. W tym momencie musimy stworzyć nowy Period i dodać do niego tworzonego Sheeta.

Wydaje mi się, że ta logika powinna być w modelu (element nadrzędny Document, który trzyma Periody). Jednak rozwala mnie tu ten Localizer, którego nie powinno tu być. No, ale z tego wynika, że przez Localizer ta logika nie powinna być w modelu.

Dlaczego Sheet dziedziczy po Period? Sheet też może mieć listę Sheetów? - Tyvrel 2019-03-06 09:39
Dziedziczy po period, bo ma wiele pól wspólnych. Daje coś nowego i nie ma "dzieci". Ale Period może mieć w sobie inne Periody. I na podstawie listy ustala swoje daty i robi proste obliczenia - Juhas 2019-03-06 12:04
Mnie bardziej ciekawi dlaczego chcesz używać lokalizera w domenie, jak rozumiem. - Gworys 2019-03-06 16:38
No właśnie nie za bardzo chce. Ale nie widzę normalnego sposobu, żeby zrobić to inaczej. Sheet ma swoją nazwę. Nazwa ma być brana z tłumaczeń. - Juhas 2019-03-06 16:43

Pozostało 580 znaków

2019-03-06 01:09
0

Na pewno nie w Domain Modelu. Powinieneś mieć usługę, coś w stylu:

SheetTranslator.Translate(AnyValues); // return sheet, czy coś tam...

Do której wstrzykujesz ILocalizer.
Jeśli przeszkadza ci nie taki namespace to zaimplementuj to w warstwie infrastruktury.

Ograniczenie do 12 widzę jako specyfikację albo politykę, którą przekazujesz do Domain Modelu albo Fabryki.

Potem idzie fabryka, która spina specyfikacje i translator.

SheetFactory.Sheet(Allow12Items, AnyValues); // czy tam periodFactory...

To tak mniej więcej, zbyt dużo nie napisałeś. Czy pomogłem?


Unhandled Exception: System.MissingMethodException: Constructor on type 'System.Exception' not found.
edytowany 4x, ostatnio: Gworys, 2019-03-06 03:56

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0