2010-07-16 23 views
5

Tôi muốn xác thực một số đối tượng. Xác nhận có hai phần:Giải pháp thiết kế cần thiết cho Kịch bản xác nhận

  • xác nhận cho dù người dùng có quyền truy cập vào các đối tượng (các quyền cụ thể đã được tính toán và lưu trữ trong các giá trị boolean, có tối đa 4 vai trò)
  • kiểm tra nếu đối tượng là trong một trạng thái nhất định (từ một tập các trạng thái)

tôi có rất nhiều các quy tắc (trên thực tế khoảng 25 trong tổng số) giống như những người dưới đây mà cần phải được xác nhận:

  • isOwner & & (trạng thái == 11 || status == 13 || tình trạng == 14)
  • ! (isOwner & & isReceiver & & status == 12)
  • .....

Tôi đã những quy tắc trải ra trong một số phương pháp, 4 hoặc 5 quy tắc trong một phương pháp. Nếu quy tắc không thành công thì các quy tắc khác sẽ không được chọn. Tôi cần xây dựng trình xác thực (hoặc thiết lập một trình xác thực đã được xây dựng) trong mọi phương thức sử dụng xác thực này.

Tôi đang tìm mẫu thiết kế có thể giúp xây dựng cấu trúc để xác thực đối tượng dễ dàng hơn. Mục tiêu của tôi là có thể cung cấp các thông báo lỗi cụ thể. Ví dụ: nếu xác thực không thành công vì người dùng không có quyền thì tôi muốn cho họ biết điều này. Nếu nó không thành công vì trạng thái của đối tượng thì tôi muốn hiển thị .

Đầu tiên tôi mặc dù kiểu trang trí. Tôi có một đối tượng xử lý thông báo lỗi có thể được trang trí với các thông báo lỗi cụ thể. Một người trang trí sẽ kiểm tra quyền của người dùng và một người khác cho các tiểu bang. Nhưng thứ tự mà tôi đang xây dựng các đối tượng validator không quan trọng nên sức mạnh của pattern decorator không được sử dụng. (AFAIK đây là một lợi thế lớn của việc sử dụng trang trí - trộn đồ trang trí). Tôi nghĩ rằng một chuỗi có thể tốt hơn cho trường hợp này ...?!?! Bạn muốn giới thiệu thiết kế thay thế nào cho kịch bản này?

+0

Bạn đang sử dụng .net và C#? – garik

+0

@igor: nó có quan trọng không? – cherouvim

+0

@igor: Tôi nghĩ điều đó không quan trọng, ý tưởng này được áp dụng ở mọi ngôn ngữ. BTW Tôi đang sử dụng Java. – Atticus

Trả lời

2

Thay vì suy nghĩ về cách sử dụng mẫu nào, hãy suy nghĩ xem đối tượng nào có ý nghĩa và hành vi của chúng nên như thế nào.

Trong trường hợp này, những gì bạn muốn làm là chuyển đối tượng cho một loạt quy tắc. Nếu nó không thành công một trong các quy tắc, điều đó sẽ kích hoạt một thông báo, và phần còn lại của các quy tắc không được kiểm tra (có đúng không)?

Nếu vậy, bạn sẽ nhận thấy rằng những gì chúng ta không nói về một kịch bản nơi dữ liệu được truyền cho tất cả các quy tắc trong chuỗi ... đó là dấu hiệu của một chuỗi mẫu lệnh, thay vì trang trí.

Mặt khác, nếu bạn muốn chuyển nó cho tất cả các quy tắc, nó nghe với tôi gần như giống như một mô hình khách truy cập.

Hãy suy nghĩ về giải pháp lý tưởng và sau đó xác định mẫu. Đừng bắt đầu bằng cách cố gắng tìm một mẫu để áp dụng.

+0

Nếu quy tắc không thành công thì phần còn lại của quy tắc sẽ không được chọn. Tôi không nhất thiết cần một mẫu thiết kế mà tôi muốn biết cái gì có thể là cấu trúc tốt nhất cho kịch bản này? – Atticus

+1

@Atticus: Nếu quy tắc quyết định 'xử lý' đối tượng, nó sẽ gửi một thông báo và dừng quy tắc xử lý. Nếu không, nó sẽ đưa nó vào quy tắc tiếp theo ... nghe giống như một Chain of Command cổ điển. – kyoryu

+0

Ok, điều này nghe có vẻ khá tốt cho kịch bản này. Tôi có thể tạo các lệnh của mình hoặc gọi chúng là các trình xử lý và đặt chúng trong một chuỗi. Tôi sẽ có một lớp chuỗi trừu tượng hoặc có thể là giao diện sẽ có phương thức xác thực. Câu hỏi khác của tôi là khi nào tôi nên lưu trữ các vai trò và trạng thái chuẩn mà tôi đang so sánh mọi thứ trong các lớp lệnh hoặc trình xử lý. Tôi có nên đặt chúng trong lớp trừu tượng mà từ đó tất cả các lệnh/trình xử lý được bắt nguồn không? Hay những lớp xử lý này sẽ lấy chúng từ nơi khác? – Atticus

1

Bạn nên sử dụng mẫu chiến lược cho trường hợp này vì bạn cần các thuật toán khác nhau cho vai trò người dùng đã cho (isOwner) và mã trạng thái.

+0

Tôi không cần thuật toán cho mã trạng thái. Trình xác thực cho mã trạng thái chỉ đơn giản là kiểm tra xem trạng thái có phải là một trong các trạng thái được cho phép hay không. Nó chỉ đơn giản là kiểm tra xem trạng thái của đối tượng có nằm trong danh sách hay không. Danh sách là các đối tượng đang thay đổi từ trình duyệt tính hợp lệ thành trình xác nhận hợp lệ. – Atticus

+0

Ok, vì vậy bạn có thể loại bỏ tình trạng từ phù thủy nhà máy sẽ khởi tạo chiến lược cụ thể. –

+0

Vì vậy, bạn có nghĩa là một mô hình nhà máy kết hợp với stratergy? – Atticus

1

Tôi sẽ sử dụng chuỗi trách nhiệm. Bạn làm cho đối tượng của bạn đi qua chuỗi.

1

Sử dụng chiến lược (ví dụ: danh sách hoặc quy tắc cần kiểm tra) + máy trạng thái (ví dụ: liệt kê với sản lượng (.net)).

class Program 
    { 
     public class StateObject 
     { 
      public virtual int State { get; set; } 
     } 

     public abstract class Rule 
     { 
      public abstract Result Check(StateObject objectToBeChecked); 

     } 

     public class DefaultAllow : Rule 
     { 
      public override Result Check(StateObject objectToBeChecked) 
      { 
       Console.WriteLine("DefaultAllow: allow"); 
       return Result.Allow; 
      } 
     } 

     public class DefaultDeny : Rule 
     { 
      public override Result Check(StateObject objectToBeChecked) 
      { 
       Console.WriteLine("DefaultDeny: deny"); 
       return Result.Deny; 
      } 
     } 

     public class DefaultState : Rule 
     { 
      public override Result Check(StateObject objectToBeChecked) 
      { 
       Console.WriteLine("DefaultState: state: {0}", objectToBeChecked.State); 
       return objectToBeChecked.State == 1 ? Result.Allow : Result.Deny; 
      } 
     } 

     public class Strategy 
     { 

      public virtual IEnumerable<Rule> GetRules() 
      { 
       return new List<Rule>() 
          { 
           new DefaultAllow(), 
           new DefaultState() 
          }; 
      } 
     } 

     public class Validator 
     { 
      private readonly Strategy _strategy; 

      public Validator(Strategy strategy) 
      { 
       _strategy = strategy; 
      } 

      public IEnumerable<Result> Process(StateObject objectToBeChecked) 
      { 
       foreach (Rule rule in _strategy.GetRules()) 
        yield return rule.Check(objectToBeChecked); 
      } 

     } 

     public class MyStateMachine 
     { 
      private readonly Validator _validator; 
      private StateObject _stateObject; 

      public event EventHandler OnAllow; 
      public event EventHandler OnDeny; 
      public event EventHandler OnError; 

      public MyStateMachine(Validator validator) 
      { 
       _validator = validator; 
      } 

      public void Init(StateObject stateObject) 
      { 
       _stateObject = stateObject; 
      } 

      protected virtual void Validate() 
      { 
       Result result = Result.Allow; // default 

       foreach (Result r in _validator.Process(_stateObject)) 
       { 
        result = r; 
        if (r != Result.Allow) 
         break; 
       } 

       if (result == Result.Allow) 
        Notify(OnAllow); 
       else if (result == Result.Deny) 
        Notify(OnDeny); 
       else if (result == Result.Error) 
        Notify(OnError); 
       else 
        throw new NotSupportedException(); 

       Console.WriteLine("Result: {0}", result); 
      } 


      private void Notify(EventHandler handler) 
      { 
       if (handler != null) 
        handler.Invoke(_stateObject, EventArgs.Empty); 
      } 


      public void ChangeState(int prevState, int newState) 
      { 
       if (prevState != _stateObject.State) 
        throw new InvalidStateException(); 

       _stateObject.State = newState; 

       Validate(); // maybe this, maybe before assign a new state 
      } 
     } 

     public class InvalidStateException : Exception { } 

     public enum Result { Allow, Deny, Error } 


     static void Main(string[] args) 
     { 
      Strategy defaultStrategy = new Strategy(); 
      Validator ruleChecker = new Validator(defaultStrategy); 
      MyStateMachine stateMachine = new MyStateMachine(ruleChecker); 

      StateObject objectToBeChecked = new StateObject(); 
      stateMachine.Init(objectToBeChecked); 

      stateMachine.ChangeState(objectToBeChecked.State, 1); 
      stateMachine.ChangeState(objectToBeChecked.State, 2); 


      Console.ReadLine(); 
     } 
    } 
0

Tôi có thể sử dụng Mẫu đặc điểm kỹ thuật từ DDD và sau đó sử dụng một cái gì đó giống như Đặc tả tổng hợp để kết nối tất cả các phần khác nhau mà bạn cần.

Check out this thread

Các vấn đề liên quan