Dostosowuję projektowanie oparte na domenie od około 8 lat i nawet po tylu latach wciąż mnie wkurza. To sprawdza unikalny rekord w przechowywaniu danych w stosunku do obiektu domeny.
We wrześniu 2013 r. Martin Fowler wspomniał o zasadzie TellDon'tAsk , która, jeśli to możliwe, powinna być stosowana do wszystkich obiektów domeny, która powinna następnie zwrócić komunikat o przebiegu operacji (w projektowaniu obiektowym odbywa się to głównie poprzez wyjątki, gdy operacja zakończyła się niepowodzeniem).
Moje projekty są zwykle podzielone na wiele części, przy czym dwie z nich to Domena (zawierająca reguły biznesowe i nic więcej, domena jest całkowicie ignorancka) i Usługi. Usługi znające warstwę repozytorium używaną do danych CRUD.
Ponieważ unikalność atrybutu należącego do obiektu jest domeną / regułą biznesową, moduł domeny powinien być długi, więc reguła jest dokładnie tam, gdzie powinna być.
Aby móc sprawdzić unikatowość rekordu, musisz zapytać o aktualny zestaw danych, zwykle bazę danych, aby dowiedzieć się, czy Name
istnieje już inny rekord z na przykład powiedzmy .
Biorąc pod uwagę, że warstwa domeny jest uporczywa w ignorancji i nie ma pojęcia, jak odzyskać dane, ale tylko jak wykonać na nich operacje, tak naprawdę nie może dotknąć samych repozytoriów.
Projekt, który następnie dostosowywałem, wygląda następująco:
class ProductRepository
{
// throws Repository.RecordNotFoundException
public Product GetBySKU(string sku);
}
class ProductCrudService
{
private ProductRepository pr;
public ProductCrudService(ProductRepository repository)
{
pr = repository;
}
public void SaveProduct(Domain.Product product)
{
try {
pr.GetBySKU(product.SKU);
throw Service.ProductWithSKUAlreadyExistsException("msg");
} catch (Repository.RecordNotFoundException e) {
// suppress/log exception
}
pr.MarkFresh(product);
pr.ProcessChanges();
}
}
Prowadzi to do tego, że usługi definiują reguły domeny zamiast samej warstwy domeny, a reguły są rozproszone po wielu sekcjach kodu.
Wspomniałem o zasadzie TellDon'tAsk, ponieważ jak widać, usługa oferuje akcję (zapisuje Product
lub zgłasza wyjątek), ale w metodzie operujesz na obiektach przy użyciu podejścia proceduralnego.
Oczywistym rozwiązaniem jest utworzenie Domain.ProductCollection
klasy za pomocą Add(Domain.Product)
metody rzucającej ProductWithSKUAlreadyExistsException
, ale bardzo brakuje jej wydajności, ponieważ trzeba by uzyskać wszystkie Produkty z przechowywania danych, aby dowiedzieć się w kodzie, czy Produkt ma już tę samą SKU jako produkt, który próbujesz dodać.
Jak rozwiązujecie ten konkretny problem? Sam w sobie nie stanowi to problemu, ponieważ warstwa usług reprezentuje pewne reguły domenowe od lat. Warstwa usługowa zazwyczaj obsługuje również bardziej złożone operacje na domenach, po prostu zastanawiam się, czy natknąłeś się na lepsze, bardziej scentralizowane rozwiązanie podczas swojej kariery.