2012-12-18 14 views
15

Tôi đang thiết kế một gói mà tôi muốn cung cấp một API dựa trên mẫu người quan sát: có nghĩa là, có những điểm mà tôi muốn phát ra tín hiệu sẽ kích hoạt số không hoặc các bên quan tâm hơn. Những bên quan tâm đó không nhất thiết cần phải biết về nhau.Có cách nào ưu tiên để thiết kế các API tín hiệu hoặc sự kiện trong Go?

Tôi biết tôi có thể triển khai API như thế này từ đầu (ví dụ: sử dụng bộ sưu tập kênh hoặc chức năng gọi lại), nhưng đã tự hỏi liệu có cách nào thích hợp hơn để cấu trúc các API đó hay không.

Trong nhiều ngôn ngữ hoặc khuôn khổ tôi đã từng chơi, đã có các cách tiêu chuẩn để xây dựng các API này để chúng hoạt động theo cách người dùng mong đợi: ví dụ: các hàm g_signal_* cho các ứng dụng dựa trên glib, các sự kiện và addEventListener() cho các ứng dụng JavaScript DOM hoặc các đại biểu multicast cho .NET.

Có điều gì tương tự cho Go không? Nếu không, liệu có cách nào khác để cấu trúc loại API này là thành ngữ hơn trong Go?

Trả lời

15

Tôi sẽ nói rằng một goroutine nhận được từ một kênh là một tương tự của một người quan sát đến mức độ nhất định. Một cách thành ngữ để trưng bày các sự kiện trong Go sẽ là IMHO để trả về các kênh từ một gói (hàm). Một quan sát khác là callbacks không được sử dụng quá thường xuyên trong các chương trình Go. Một trong những lý do là sự tồn tại của select statement mạnh mẽ.

Như tôi lưu ý cuối cùng: một số người (tôi cũng vậy) xem xét các mẫu GoF như các mẫu đơn chống Go.

+2

Tôi nghĩ rằng câu trả lời này bao gồm một số trường hợp sử dụng, nhưng tôi chắc chắn muốn nghe thêm ý kiến ​​/ câu trả lời về vấn đề này. Các kênh gây thêm gánh nặng cho người gọi ("người quan sát"), vì nó phải bắt đầu một goroutine chờ đợi trên kênh này. Nếu cùng một chức năng có thể xử lý nhiều "sự kiện", điều này có thể trở nên rườm rà. Như một ví dụ ngược lại, các cuộc gọi lại được sử dụng trong net/http cho các trình xử lý HTTP. Có những trường hợp sử dụng mà chúng làm cho IMHO có ý nghĩa hơn. – mna

+0

Tôi chỉ sử dụng thuật ngữ "quan sát mẫu" vì nó là thuật ngữ mà mọi người có thể hiểu: Tôi không viết các chương trình của tôi bằng cách phá vỡ chúng thành các mẫu thiết kế có tên, nếu đó là những gì bạn nhận được. Theo như đề xuất API của bạn, tôi có thể thấy cách một hàm trả về các kênh đọc có thể hoạt động cho phía đăng ký, nhưng bạn sẽ mô hình hóa API hủy đăng ký phù hợp như thế nào? –

+5

Các kênh có thể so sánh được với sự bình đẳng và chúng là đối tượng lớp đầu tiên. Để hủy đăng ký, chỉ cần chuyển kênh trở lại nhà xuất bản, nó có thể tìm thấy hồ sơ của kênh và thực hiện hành động thích hợp để chấm dứt đăng ký. – Sonia

4

Go cung cấp cho bạn rất nhiều công cụ để thiết kế api tín hiệu.

Trước tiên, bạn phải quyết định một số điều:

Bạn có muốn mô hình đẩy hoặc kéo không? ví dụ. Nhà xuất bản có đẩy sự kiện vào người đăng ký hay người đăng ký kéo sự kiện từ nhà xuất bản không?

Nếu bạn muốn có hệ thống đẩy thì người đăng ký sẽ cung cấp cho nhà xuất bản kênh để gửi tin nhắn sẽ hoạt động thực sự tốt. Nếu bạn muốn một phương pháp kéo thì chỉ một hộp thông báo được bảo vệ bằng một mutex sẽ hoạt động. Khác với điều đó mà không cần biết thêm về yêu cầu của bạn thật khó để đưa ra nhiều chi tiết hơn.

+0

Đối với trường hợp sử dụng cụ thể của tôi, nhà xuất bản sẽ phát các sự kiện và người đăng ký phản ứng sớm nhất có thể. Đó là một trường hợp tương tác sẽ quan trọng hơn thông lượng, nếu đó là những gì bạn đang yêu cầu. –

1

Tôi sẽ nói không có cách nào tiêu chuẩn để làm điều này vì kênh được tích hợp vào ngôn ngữ. Không có thư viện kênh nào có cách làm việc tiêu chuẩn với kênh, chỉ đơn giản là kênh. Có các kênh như được xây dựng trong các đối tượng lớp học đầu tiên giải phóng bạn khỏi phải làm việc với các kỹ thuật tiêu chuẩn và cho phép bạn giải quyết các vấn đề theo cách tự nhiên đơn giản nhất.

+0

Tôi biết về các kênh (tôi thậm chí đã đề cập đến chúng trong câu hỏi). Nhưng các kênh thực sự chỉ cung cấp một cơ chế giao tiếp 1-1, trong khi tôi muốn 1-nhiều (nhiều nơi có thể bằng không). Vì vậy, tôi thực sự không thể tạo kênh API và không có gì khác. –

+1

Không đúng sự thật. Kênh có thể có nhiều người gửi và nhiều người nhận. Dù sao, bạn cũng có thể phàn nàn rằng các biến không tốt bởi vì chúng chỉ có thể giữ một giá trị tại một thời điểm. Bạn cần nhiều hơn? Sử dụng cấu trúc dữ liệu. Một nhà xuất bản có thể lưu trữ tất cả các thuê bao của nó trong một lát, một bản đồ, một cấu trúc cây, bất cứ điều gì có ý nghĩa trong trường hợp của bạn. Để xuất bản, lặp qua cấu trúc dữ liệu và gửi cập nhật cho từng người đăng ký. – Sonia

+0

Tôi đã đề cập đến các kênh là 1-1 theo nghĩa cho mỗi thông báo, kênh kết nối một người gửi với một người nhận. Mặc dù bạn chắc chắn có thể sử dụng nhiều người nhận để ví dụ: phân chia công việc giữa goroutines, đó rõ ràng không phải là những gì tôi đã hỏi về. –

3

Tôi cần một kiểu "kiểu quan sát" trong một vài dự án. Here's a reusable example từ một dự án gần đây.

Có một thử nghiệm tương ứng cho biết cách sử dụng nó.

Lý thuyết cơ bản là một trình phát sự kiện gọi Submit với một số đoạn dữ liệu bất cứ khi nào có điều gì đó thú vị xảy ra. Bất kỳ khách hàng nào muốn biết sự kiện đó sẽ Register một kênh mà nó đọc dữ liệu sự kiện. Kênh này bạn đã đăng ký có thể được sử dụng trong vòng lặp select hoặc bạn có thể đọc trực tiếp kênh này (hoặc bộ đệm và thăm dò ý kiến).

Khi bạn hoàn tất, bạn Unregister.

Không hoàn hảo cho tất cả các trường hợp (ví dụ:Tôi có thể muốn một loại sự kiện không đăng ký lực lượng cho các nhà quan sát chậm), nhưng nó hoạt động ở nơi tôi sử dụng nó.

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