Statyczna zależność w modelu

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?

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;
	}
}
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.

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.

0

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

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.

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?

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