2012-01-09 19 views
7

Tôi muốn thực hiện một hệ thống xác nhận đơn giản cho các lớp học nhất định của các đối tượng, về cơ bảnCác giải pháp khác cho thiết kế quy tắc sau là gì?

public interface IMyClassRule { 
    bool IsValid(MyClass obj, Context someAdditionalData) 
} 

Danh sách các quy tắc là tính năng tự động phát hiện sử dụng khuôn khổ DI và không ấn định trước.

Giả sử tôi có VeryGeneralDefaultRuleAboutAllObjects : IMyClassRuleSpecificCaseWhenGeneralRuleDoesNotApply : IMyClassRule. Làm thế nào tôi có thể xử lý giải pháp này một cách chung chung (về cơ bản cho phép ghi đè lên bất kỳ quy tắc của bất kỳ quy tắc khác trong trường hợp nhất định)?

Solutions tôi coi:

  1. ưu tiên Numeric cho các quy tắc hay quy tắc kết quả

    Pro: Đơn giản để hiểu và thực hiện.
    Contra: Tôi cần phải biết/đoán mức ưu tiên của quy tắc ban đầu. Không rõ ràng ưu tiên nào là đầu tiên (1 hoặc 1000)? Cần một số kết quả quy tắc "không quan tâm" cho trường hợp không áp dụng trường hợp cụ thể.

  2. Loại ưu tiên dựa trên (về cơ bản .Before<VeryGeneralRule>)

    Pro: Cụ thể tuyên bố những gì bạn muốn đạt được.
    Contra: Cần tham chiếu rõ ràng đến quy tắc ban đầu. Logic đặt hàng sẽ phức tạp. Cần một số kết quả quy tắc "không quan tâm" cho trường hợp không áp dụng trường hợp cụ thể.

Có tùy chọn nào khác/tốt hơn không?

+1

Rất gây phiền nhiễu vấn đề. Tôi đã tranh luận về điều này trong nhiều giờ, và đã không đi đến một giải pháp thỏa đáng. – CodesInChaos

+2

Cân nhắc việc từ bỏ tự động phát hiện và tạo thủ công danh sách quy tắc trung tâm theo thứ tự ưu tiên. – CodesInChaos

+0

Nhìn vào khái niệm về quy tắc Web (http://rule.codeeffects.com). Tôi nghĩ rằng bạn đang tìm kiếm một cái gì đó tương tự như những gì họ làm. – Kizz

Trả lời

0

Cách thêm khả năng đưa một số điều kiện vào các trường hợp quy tắc, ví dụ: các giao diện của giao diện IRuleApplicability. Bạn có thể kết hợp nó với thứ gì đó tương tự như # 2 và sử dụng một lớp cơ sở của tất cả các quy tắc để kiểm tra khả năng áp dụng trước khi áp dụng quy tắc.

2

Tôi nghĩ rằng rất nhiều điều này sẽ phụ thuộc vào phạm vi của dự án và chỉ cần làm thế nào lỏng lẻo cùng bạn cần phải được. Tôi làm rất nhiều công việc xung quanh các quy tắc kinh doanh và họ cần phải mở rộng càng tốt. Tôi sẽ không buộc mình vào một hệ thống quy tắc thứ tự nếu có ngay cả khối lượng nhỏ nhất của các quy tắc, hoặc thứ tự của chúng thậm chí còn phức tạp từ xa. Tôi nghĩ rằng tự động phát hiện/hệ thống dây điện của các quy tắc là hoàn toàn là cách để đi ở đây.

Chìa khóa cho loại tình huống này, theo ý kiến ​​của tôi, là các quy tắc trường hợp chung là không phải được xác định bởi sự thiếu logic liên quan đến phạm vi của chúng. Các quy tắc trường hợp chung phải có logic phạm vi cũng giống như quy tắc cụ thể của từng trường hợp cụ thể. Chúng có thể nằm trong phạm vi 99 trên 100 lần, nhưng chúng vẫn cần có logic phạm vi cụ thể.

Sau đây là cách tôi tiếp cận điều này. Tôi không hồi hộp với InnerScope() được gắn trực tiếp với IRule, nhưng với điều kiện bạn đang xem xét một danh sách thứ tự, tôi giả sử logic có thể quản lý và tương đối tĩnh hoặc bạn có thể tiêm một đại biểu cho logic đó.

Khung giao diện

public interface IRule<in T>{ 
    bool IsValid(T obj); 
    bool WithinScope(); 
} 

public interface IValidator<in T>{ 
    bool IsValid(T obj); 
} 

public interface IRuleFactory<in T>{ 
    IEnumerable<IRule<T>> BuildRules(); 
} 

Generic Validator và Quy tắc Factory

public class GenericValidator<T> : IValidator<T> 
{ 
    private readonly IEnumerable<IRule<T>> _rules; 

    public GenericValidator(IRuleFactory<T> ruleFactory){ 
     _rules = ruleFactory.BuildRules(); 
    } 

    public bool IsValid(T obj){ 
     return _rules.All(p => p.IsValid(obj)); 
    } 
} 

public class GenericRuleFactory<T> : IRuleFactory<T> 
{ 
    private readonly IEnumerable<IRule<T>> _rules; 

    public GenericRuleFactory(IEnumerable<IRule<T>> rules){ 
     _rules = rules; 
    } 

    public IEnumerable<IRule<T>> BuildRules(){ 
     return _rules.Where(x => x.WithinScope()); 
    } 
} 

mẫu quy

public class VeryGeneralDefaultRuleAboutAllObjects : IRule<IMyClass> 
{ 
    private readonly Context _context; 

    public VeryGeneralDefaultRuleAboutAllObjects(Context context){ 
     _context = context;  
    } 

    public bool IsValid(IMyClass obj){ 
     return !obj.IsAllJackedUp; 
    } 

    public bool WithinScope(){ 
     return !_context.IsSpecialCase; 
    } 
} 

public class SpecificCaseWhenGeneralRuleDoesNotApply : IRule<IMyClass> 
{ 
    private readonly Context _context; 

    public VeryGeneralDefaultRuleAboutAllObjects(Context context){ 
     _context = context;  
    } 

    public bool IsValid(IMyClass obj){ 
     return !obj.IsAllJackedUp && _context.HasMoreCowbell; 
    } 

    public bool WithinScope(){ 
     return _context.IsSpecialCase; 
    } 
} 

IoC Dây (Sử dụng StructureMap)

public static class StructureMapBootstrapper 
{ 
    public static void Initialize() 
    { 
     ObjectFactory.Initialize(x => 
     { 
      x.Scan(scan => 
      { 
       scan.TheCallingAssembly(); 
       scan.AssembliesFromApplicationBaseDirectory(); 
       scan.AddAllTypesOf(typeof (IRule<>)); 
      }); 

      x.For(typeof(IValidator<>)) 
       .Use(typeof(GenericValidator<>)); 

      x.For(typeof(IRuleFactory<>)) 
       .Use(typeof(GenericRuleFactory<>)); 
     }); 
    } 
} 
+0

Gần đây tôi đã triển khai một cái gì đó trông khá giống thế này, trừ đi cấu trúc dây StructureMap phức tạp hơn. Tôi thích câu trả lời này bởi vì nó xác nhận rằng những gì tôi đã làm được xem là lành mạnh bởi ít nhất một người khác trong cộng đồng. –