Tôi đã thích nghi với thiết kế hướng tên miền trong khoảng 8 năm nay và thậm chí sau ngần ấy năm, vẫn còn một điều, điều đó đã làm tôi khó chịu. Đó là kiểm tra một bản ghi duy nhất trong lưu trữ dữ liệu đối với một đối tượng miền.
Vào tháng 9 năm 2013, Martin Fowler đã đề cập đến nguyên tắc TellD Don'tAsk , nếu có thể, nên được áp dụng cho tất cả các đối tượng miền, sau đó sẽ trả về một thông điệp, cách hoạt động (trong thiết kế hướng đối tượng, điều này chủ yếu được thực hiện thông qua các ngoại lệ, khi hoạt động không thành công).
Các dự án của tôi thường được chia thành nhiều phần, trong đó hai trong số đó là Miền (chứa các quy tắc kinh doanh và không có gì khác, tên miền hoàn toàn không biết gì) và Dịch vụ. Dịch vụ biết về lớp kho lưu trữ được sử dụng cho dữ liệu CRUD.
Bởi vì tính duy nhất của một thuộc tính thuộc về một đối tượng là một quy tắc miền / doanh nghiệp, nên nó phải dài đối với mô-đun miền, do đó quy tắc này chính xác là nơi nó được cho là.
Để có thể kiểm tra tính duy nhất của một bản ghi, bạn cần truy vấn bộ dữ liệu hiện tại, thường là cơ sở dữ liệu, để tìm hiểu xem liệu một bản ghi khác có giả sử Name
đã tồn tại hay chưa.
Xem xét lớp miền là không biết gì về sự kiên trì và không biết làm thế nào để lấy lại dữ liệu mà chỉ có cách thực hiện các thao tác trên chúng, nó thực sự không thể chạm vào các kho lưu trữ.
Thiết kế tôi đã được điều chỉnh sau đó trông như thế này:
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();
}
}
Điều này dẫn đến việc có các dịch vụ xác định quy tắc miền thay vì chính lớp miền và bạn có các quy tắc nằm rải rác trên nhiều phần của mã.
Tôi đã đề cập đến nguyên tắc TellD Don'tAsk, vì như bạn có thể thấy rõ, dịch vụ cung cấp một hành động (nó sẽ lưu Product
hoặc ném một ngoại lệ), nhưng bên trong phương thức bạn đang thao tác trên các đối tượng thông qua cách tiếp cận thủ tục.
Giải pháp rõ ràng là tạo ra một Domain.ProductCollection
lớp với một Add(Domain.Product)
phương thức ProductWithSKUAlreadyExistsException
, nhưng nó thiếu hiệu năng rất nhiều, bởi vì bạn sẽ cần lấy tất cả các Sản phẩm từ bộ lưu trữ dữ liệu để tìm ra mã, liệu một Sản phẩm có cùng SKU không là Sản phẩm bạn đang cố gắng thêm.
Làm thế nào để các bạn giải quyết vấn đề cụ thể này? Đây không thực sự là một vấn đề, tôi đã có lớp dịch vụ đại diện cho các quy tắc tên miền nhất định trong nhiều năm. Lớp dịch vụ thường cũng phục vụ các hoạt động miền phức tạp hơn, tôi chỉ đơn giản là tự hỏi liệu bạn có vấp phải một giải pháp tốt hơn, tập trung hơn trong sự nghiệp của mình không.