2010-10-11 27 views
7

Có thể triển khai mẫu lệnh GOF bằng cách sử dụng một đại biểu Queue of Action không?Thực hiện mẫu lệnh bằng cách sử dụng ủy nhiệm C# Action

Tôi đã cố gắng để quấn đầu của tôi xung quanh nó một lúc và tôi stumped bởi vì mỗi hành động có thể tôi muốn thêm vào hàng đợi có thể có một số lượng tham số.

Mọi đề xuất? Tôi đang sủa cây sai bằng cách tập trung vào mẫu lệnh?

UPDATE:

Rất cám ơn jgauffin, nó hoạt động một điều trị ... thực hiện của tôi bây giờ trông giống như

public class CommandDispatcher 
{ 
    private readonly Dictionary<Type, List<Action<ICommand>>> _registeredCommands = 
     new Dictionary<Type, List<Action<ICommand>>>(); 

    public void RegisterCommand<T>(Action<ICommand> action) where T : ICommand 
    { 
     if (_registeredCommands.ContainsKey(typeof (T))) 
      _registeredCommands[typeof (T)].Add(action); 
     else 
      _registeredCommands.Add(typeof (T), new List<Action<ICommand>> {action}); 
    } 

    public void Trigger<T>(T command) where T : ICommand 
    { 
     if (!_registeredCommands.ContainsKey(typeof(T))) 
      throw new InvalidOperationException("There are no subscribers for that command"); 

     foreach (var registeredCommand in _registeredCommands[typeof(T)]) 
     { 
      registeredCommand(command); 
      if (command.Cancel) break; 
     } 
    } 
} 

Trả lời

10

Bạn có thể sử dụng Hành động. Bạn không nên sử dụng nhiều thông số. Điều gì sẽ xảy ra nếu một lệnh cần một tham số mới? Sau đó, bạn sẽ cần phải thay đổi tất cả các địa điểm gọi lệnh cộng với trình xử lý.

Thay vào đó, bạn nên sử dụng các lớp Lệnh có tất cả tham số làm thuộc tính. Bằng cách này, bạn có thể thêm các tham số mà không có nó ảnh hưởng đến mã (các thông số mới nên được coi là tùy chọn trong trình xử lý).

đây là cách tôi sẽ làm điều đó:

public interface ICommand 
{ 
    // Cancel processing, do not invoke any more handlers 
    public bool Cancel { get; set; } 
} 

public class CommandDispatcher 
{ 
    private Dictionary<Type, List<Action<ICommand>>> _commands = new Dictionary<Type, List<Action<ICommand>>>(); 


    // Add to dictionary here 
    public void Subscribe<T>(Action<T> action) where T : ICommand 
    { 
     List<Action<ICommand>> subscribers; 
     if (!_commands.TryGetValue(typeof(T), out subscribers)) 
     { 
      subscribers = new List<Action<ICommand>>(); 
      _commands.Add(typeof(T), subscribers)); 
     } 

     subscribers.Add(action); 
    } 

    // find command and to foreach to execute the actions  
    public void Trigger<T>(T command) where T : ICommand 
    { 
     List<Action<ICommand>> subscribers; 
     if (!_commands.TryGetValue(typeof(T), out subscribers)) 
      throw new InvalidOperationException("There are no subscribers for that command"); 

     foreach(var subsriber in subscribers) 
     { 
      subscriber(command); 
      if (command.Cancel) 
       break; //a handler canceled the command to prevent others from processing it. 
     } 
    } 

} 

public class AddTextCommand : ICommand 
{ 
    public string TextToAdd {get;set;} 
} 

public class TextHandler 
{ 
    public TextHandler(CommandDispatcher dispatcher) 
    { 
     disptacher.Subscribe<AddTextCommand>(OnAddText); 
    } 

    public void OnAddText(AddTextCommand cmd) 
    { 
     //.... 
    } 
} 


public partial class MyForm : Form 
{ 
    CommandDispatcher _dispatcher; 

    private void MyTextBox_Changed(object source, EventArgs e) 
    { 
     _dispatcher.Trigger(new AddTextCommand{TextToAdd = MyTextBox.Text}=; 
    } 
} 

Lưu ý rằng mã là loại pseudo-code. Tôi đã viết nó trực tiếp trong câu trả lời mà không kiểm tra nó. Bạn có thể sẽ phải thay đổi công cụ để có được nó làm việc, nhưng nó ít nhất phải cung cấp cho bạn một gợi ý. Việc triển khai cho phép bạn thêm nhiều người đăng ký cho mỗi lệnh.

+0

Điều này có vẻ giống như một giải pháp thú vị, bạn có muốn xây dựng phương pháp kích hoạt sẽ hoạt động như thế nào không? lệnh (T) hoặc command.Invoke()? Và tại sao một từ điển của _commands, tại sao không chỉ là một Danh sách thẳng hoặc Hàng đợi? – Dve

+0

Từ điển nhanh hơn, bạn không phải tự mình duyệt qua bộ sưu tập để tìm đúng loại lệnh (và là người đăng ký) – jgauffin

+0

Tôi đã thêm các triển khai. Chúng có thể không hoạt động 100%. Cố gắng làm cho nó hoạt động. – jgauffin

1

Nếu bạn lo ngại với số lượng tham số, sau đó thực hiện tốt mô hình lệnh sử dụng một lớp học sẽ là con đường đúng đắn để đi. Các đại biểu Action được giới hạn chỉ một. Ngoài ra, nếu bạn sử dụng đại biểu Action, bạn có thể muốn triển khai Hoàn tác sau mà bạn sẽ không thể làm vì bạn vừa sử dụng một đại biểu thay vì một lớp.

3

Trong mẫu lệnh, giao diện lệnh điển hình sẽ có phương thức thực thi đơn giản - điều này có thể được đại diện bởi đại biểu Hành động. Nhưng thực tế thực tế sẽ được cung cấp bởi các lớp cụ thể khác nhau, nơi bạn sẽ/có thể vượt qua các tham số (ví dụ, thông qua constructor). Ví dụ:

public interface ICommand 
{ 
    public void Execute(); 
} 

public class Command1 : ICommand 
{ 
    public Command1(int param1, string param2) 
    { 
    } 

    ... 
} 

public class Command2 : ICommand 
{ 
    ... 
} 

public class Program 
{ 

    public static void Main() 
    { 

     ... 

     var commands = new List<Action>(); 
     commands.Add((new Command1(3, "Hello")).Execute); 
     commands.Add((new Command2(...)).Execute); 

     ... 
    } 


} 

Điểm ở đây là lệnh liên quan đến trạng thái và triển khai sẽ được đóng gói trong thực hiện khác nhau trong khi Đại biểu hành động sẽ trỏ đến phương pháp thể hiện của nó. Vì vậy, gọi các đại biểu sẽ dẫn đến thực hiện lệnh.

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