2009-02-05 35 views
53

Làm cách nào để bạn xử lý xác thực trên các tập hợp phức tạp trong thiết kế do miền điều khiển? Bạn có củng cố các quy tắc kinh doanh/logic xác nhận của mình không?Xác thực trong Thiết kế Điều khiển Tên miền

Tôi hiểu xác thực đối số. Và tôi hiểu xác nhận thuộc tính có thể được gắn vào chính các mô hình và thực hiện những việc như kiểm tra xem địa chỉ email hoặc mã zip có hợp lệ không hoặc tên đầu tiên có độ dài tối thiểu và tối đa.

Nhưng điều gì về việc xác thực phức tạp liên quan đến nhiều mô hình? Bạn thường đặt những quy tắc này ở đâu theo phương pháp & trong kiến ​​trúc của mình? Và bạn sẽ sử dụng mẫu nào để triển khai chúng?

Trả lời

36

Tôi thích giải pháp Jimmy Bogard của vấn đề này. Ông có một bài đăng trên blog của mình có tiêu đề "Entity validation with visitors and extension methods", trong đó ông trình bày một cách tiếp cận rất thanh lịch để xác thực thực thể đề xuất việc triển khai một lớp riêng biệt để lưu trữ mã xác nhận.

public interface IValidator<T> 
{ 
    bool IsValid(T entity); 
    IEnumerable<string> BrokenRules(T entity); 
} 

public class OrderPersistenceValidator : IValidator<Order> 
{ 
    public bool IsValid(Order entity) 
    { 
     return BrokenRules(entity).Count() == 0; 
    } 

    public IEnumerable<string> BrokenRules(Order entity) 
    { 
     if (entity.Id < 0) 
      yield return "Id cannot be less than 0."; 

     if (string.IsNullOrEmpty(entity.Customer)) 
      yield return "Must include a customer."; 

     yield break; 
    } 
} 
+0

Cách tiếp cận được mô tả trong bài viết của Bogard trông khá tiện dụng. Cám ơn. –

+0

+1 Giải pháp tuyệt vời – 7wp

+12

Một điều mặc dù, không nên dòng 'trả về BrokenRules (thực thể) .Count()> 0' thực sự là' trả về BrokenRules (thực thể) .Count() <= 0'? – 7wp

6

tôi thường là sử dụng một lớp đặc điểm kỹ thuật, nó cung cấp một phương pháp (đây là C# nhưng bạn có thể dịch nó trong bất kỳ ngôn ngữ):

bool IsVerifiedBy(TEntity candidate) 

Phương pháp này thực hiện một kiểm tra toàn bộ các ứng cử viên và quan hệ của nó. Bạn có thể sử dụng lập luận trong lớp đặc điểm kỹ thuật để làm cho nó parametrized, giống như một mức độ kiểm tra ...

Bạn cũng có thể thêm một phương pháp để biết lý do tại sao các ứng cử viên không xác minh đặc điểm kỹ thuật:

IEnumerable<string> BrokenRules(TEntity canditate) 

Bạn chỉ đơn giản là có thể quyết định để thực hiện các phương pháp đầu tiên như thế này:

bool IsVerifiedBy(TEntity candidate) 
{ 
    return BrokenRules(candidate).IsEmpty(); 
} 

Đối với quy tắc bị phá vỡ, tôi thường là viết một iterator:

IEnumerable<string> BrokenRules(TEntity candidate) 
{ 
    if (someComplexCondition) 
     yield return "Message describing cleary what is wrong..."; 
    if (someOtherCondition) 
     yield return 
    string.Format("The amount should not be {0} when the state is {1}", 
     amount, state); 
} 

Để bản địa hóa, bạn nên sử dụng tài nguyên và tại sao không chuyển văn hóa sang phương pháp BrokenRules. Tôi đặt các lớp này vào không gian tên mô hình với các tên đề xuất sử dụng chúng.

54

Thay vì dựa vào IsValid(xx) gọi khắp nơi ứng dụng của bạn, hãy xem xét tham gia một số lời khuyên từ Greg Young:

Đừng bao giờ để cho các đơn vị của bạn nhận được vào một trạng thái không hợp lệ.

Điều này về cơ bản có nghĩa là bạn chuyển từ suy nghĩ của các thực thể thành vùng chứa dữ liệu thuần túy và nhiều hơn nữa về các đối tượng có hành vi.

Hãy xem xét ví dụ về địa chỉ của một người:.

person.Address = "123 my street"; 
person.City = "Houston"; 
person.State = "TX"; 
person.Zip = 12345; 

giữa bất kỳ của những cuộc gọi thực thể của bạn không hợp lệ (vì bạn sẽ có các tính chất đó không đồng ý với nhau Bây giờ xem xét việc này:

person.ChangeAddress(.......); 

tất cả các cuộc gọi liên quan đến hành vi thay đổi một địa chỉ hiện nay có một đơn vị nguyên tử. thực thể của bạn không bao giờ là không hợp lệ ở đây.

Nếu bạn lấy id này ea của các hành vi mô hình hơn là trạng thái, sau đó bạn có thể tiếp cận một mô hình không cho phép các thực thể không hợp lệ.

Đối với một cuộc thảo luận tốt về vấn đề này, hãy khám phá cuộc phỏng vấn InfoQ: http://www.infoq.com/interviews/greg-young-ddd

+4

Tôi luôn nghĩ rằng lời khuyên từ Greg Young mà bạn đăng không hề thực tế trong thế giới thực. –

+8

Anh ấy không chỉ ủng hộ nó vì nó có vẻ tốt đẹp, anh ấy có hệ thống rất lớn trong suy nghĩ này. –

+1

Hãy tưởng tượng có một đối tượng lồng vào một List <> của sự vật - 'Things'. Trong giai đoạn tiếp theo của quá trình xử lý, sau khi nó đã được lấp đầy, tôi phải đảm bảo rằng danh sách có phần tử nhất định và nó là yếu tố duy nhất thuộc loại đó. Làm thế nào tôi có thể làm cho 'Những điều' không đi vào trạng thái không hợp lệ? Là một giải pháp có thể tôi nghĩ rằng yêu cầu người dùng cung cấp đối tượng này làm phần tử đầu tiên của danh sách, nhưng tôi không thể làm điều đó. Vì vậy, đối tượng 'Things' có thể ở trạng thái chuyển đổi, nó có thể ở lại cho đến khi bắt đầu quá trình xử lý ở giai đoạn tiếp theo. Đó là lý do tại sao tôi phải xác nhận nó trước khi xử lý. – Pixar

-1

Câu hỏi này hơi cũ nhưng trong trường hợp bất kỳ ai quan tâm đến đây là cách tôi triển khai xác thực trong các lớp dịch vụ của mình.

Tôi có một phương thức xác thực trong mỗi lớp dịch vụ của mình có một thực thể và hành động được thực hiện, nếu xác thực không ngoại lệ tùy chỉnh được ném với chi tiết của các quy tắc bị hỏng.

Ví dụ DocumentService với xây dựng trong xác nhận

Tôi thích phương pháp này vì nó cho phép tôi để đặt tất cả các logic xác nhận cốt lõi của tôi ở một nơi mà giữ những điều đơn giản.

-1

Trong java thế giới bạn nên xem xét sử dụng hibernate validation

Nó là rất dễ đọc cho xác thực đơn giản

public class Car { 

    @NotNull 
    private String manufacturer; 

    @NotNull 
    @Size(min = 2, max = 14) 
    private String licensePlate; 

    @Min(2) 
    private int seatCount; 

    // ... 
} 

Đối với kiểm chứng thực phức tạp. Có mechanism để viết xác thực của riêng bạn.

package org.hibernate.validator.referenceguide.chapter02.classlevel; 

@ValidPassengerCount 
public class Car { 

    private int seatCount; 

    private List<Person> passengers; 

    //... 
} 
Các vấn đề liên quan