Trước hết, câu hỏi hay. Tôi ngưỡng mộ sự tập trung của bạn vào tiện ích thay vì mù quáng chấp nhận "thực hành tốt nhất". +1 cho điều đó.
Tôi đã đọc hướng dẫn đó trước đây. Bạn phải nhớ một cái gì đó về nó - nó chỉ là một hướng dẫn, chủ yếu dành cho những người mới tham gia C #, những người biết cách lập trình nhưng không quá quen thuộc với cách làm việc của C #. Đây không phải là một trang quy tắc vì đây là trang mô tả cách mọi thứ thường được thực hiện. Và vì họ đã thực hiện theo cách này ở mọi nơi, nên có thể nên kiên định.
Tôi sẽ đi đến điểm, trả lời câu hỏi của bạn.
Trước hết, tôi giả sử bạn đã biết giao diện là gì. Đối với một đại biểu, đủ để nói rằng đó là một cấu trúc có chứa một con trỏ được gõ vào một phương thức, cùng với một con trỏ tùy chọn cho đối tượng biểu thị this
đối số cho phương thức đó. Trong trường hợp phương thức tĩnh, con trỏ sau là null.
Ngoài ra còn có các đại biểu Multicast, giống như các đại biểu, nhưng có thể có một vài trong số các cấu trúc này được gán cho chúng (có nghĩa là một lệnh gọi Gọi trên một đại biểu đa hướng gọi tất cả các phương thức trong danh sách gọi được gán của nó).
Họ có ý nghĩa gì bởi một mẫu thiết kế sự kiện?
Chúng có nghĩa là sử dụng các sự kiện trong C # (có các từ khóa đặc biệt để triển khai một cách tinh vi mẫu cực kỳ hữu ích này). Các sự kiện trong C # được thúc đẩy bởi các đại biểu phát đa hướng.
Khi bạn xác định một sự kiện, chẳng hạn như trong ví dụ này:
class MyClass {
// Note: EventHandler is just a multicast delegate,
// that returns void and accepts (object sender, EventArgs e)!
public event EventHandler MyEvent;
public void DoSomethingThatTriggersMyEvent() {
// ... some code
var handler = MyEvent;
if (handler != null)
handler(this, EventArgs.Empty);
// ... some other code
}
}
Trình biên dịch thực sự biến đổi điều này thành đoạn mã sau:
class MyClass {
private EventHandler MyEvent = null;
public void add_MyEvent(EventHandler value) {
MyEvent += value;
}
public void remove_MyEvent(EventHandler value) {
MyEvent -= value;
}
public void DoSomethingThatTriggersMyEvent() {
// ... some code
var handler = MyEvent;
if (handler != null)
handler(this, EventArgs.Empty);
// ... some other code
}
}
Sau đó, bạn đăng ký một sự kiện bằng cách làm
MyClass instance = new MyClass();
instance.MyEvent += SomeMethodInMyClass;
Mà biên dịch xuống
MyClass instance = new MyClass();
instance.add_MyEvent(new EventHandler(SomeMethodInMyClass));
Vì vậy, đó là sự kiện trong C # (hoặc .NET nói chung).
Làm thế nào các thành phần hóa ra là dễ dàng nếu một đại biểu được sử dụng?
Điều này có thể dễ dàng được chứng minh:
Giả sử bạn có một lớp phụ thuộc vào một tập hợp các hành động được truyền cho nó. Bạn có thể gói gọn những hành động đó trong một giao diện:
interface RequiredMethods {
void DoX();
int DoY();
};
Và bất cứ ai muốn truyền các hành động đến lớp của bạn trước tiên sẽ phải thực hiện giao diện đó. Hoặc bạn có thể làm cho cuộc sống của họ dễ dàng hơn bằng cách phụ thuộc vào lớp sau:
sealed class RequiredMethods {
public Action DoX;
public Func<int> DoY();
}
Bằng cách này, người gọi chỉ phải tạo một thể hiện của RequestMethod và các phương thức liên kết với các đại biểu khi chạy. Đây là thường dễ dàng hơn.
Cách làm này cực kỳ có lợi trong hoàn cảnh phù hợp. Hãy suy nghĩ về nó - tại sao phụ thuộc vào một giao diện khi tất cả những gì bạn thực sự quan tâm là việc triển khai được chuyển cho bạn?
Lợi ích của việc sử dụng giao diện khi có một nhóm các phương pháp liên quan
Việc sử dụng các giao diện là có lợi vì các giao diện thường yêu cầu triển khai thời gian biên dịch rõ ràng. Điều này có nghĩa là bạn tạo một lớp mới.
Và nếu bạn có một nhóm các phương thức liên quan trong một gói, thì có ích khi gói đó được sử dụng lại bởi các phần khác của mã. Vì vậy, nếu họ có thể đơn giản khởi tạo một lớp thay vì xây dựng một nhóm đại biểu, điều đó sẽ dễ dàng hơn.
Lợi ích của việc sử dụng giao diện nếu một lớp chỉ cần một triển khai
Như đã lưu ý trước đó, các giao diện được triển khai trong thời gian biên dịch - điều đó có nghĩa là chúng hiệu quả hơn so với việc gọi một đại biểu (đó là một mức độ không xác định trên mỗi se).
"Một triển khai" có thể có nghĩa là một triển khai tồn tại một nơi được xác định rõ.
Nếu một thực hiện có thể đến từ bất cứ nơi nào trong chương trình mà chỉ xảy ra phù hợp với các phương pháp chữ ký. Điều đó cho phép linh hoạt hơn, bởi vì các phương thức chỉ cần tuân theo chữ ký dự kiến, thay vì thuộc về một lớp thực hiện rõ ràng một giao diện cụ thể. Nhưng sự linh hoạt đó có thể phải trả giá và thực sự phá vỡ nguyên tắc Thay thế Liskov , bởi vì hầu hết các lần bạn muốn làm chứng, vì nó giảm thiểu khả năng xảy ra tai nạn. Cũng giống như gõ tĩnh.
Thuật ngữ này cũng có thể đề cập đến các đại biểu phát đa hướng ở đây. Các phương thức được khai báo bởi các giao diện chỉ có thể được thực hiện một lần trong một lớp thực hiện. Nhưng các đại biểu có thể tích lũy nhiều phương thức, sẽ được gọi là tuần tự.
Vì vậy, tất cả, có vẻ như hướng dẫn không đủ thông tin, và chỉ hoạt động như những gì nó là - một hướng dẫn, không phải là một quy tắc. Một số lời khuyên thực sự có thể nghe hơi mâu thuẫn. Tùy bạn quyết định khi nào nên áp dụng cái gì. Hướng dẫn dường như chỉ cho chúng ta một con đường chung.
Tôi hy vọng câu hỏi của bạn đã được trả lời cho sự hài lòng của bạn. Và một lần nữa, danh tiếng cho câu hỏi.