2015-01-17 18 views
8

Trong Node.js, tôi có thể tạo một bản sao WordPress khá dễ dàng bằng cách sử dụng EventEmitter để nhân rộng và xây dựng một hệ thống móc vào lõi CMS, sau đó plugin có thể đính kèm.Sự kiện Golang: EventEmitter/dispatcher cho kiến ​​trúc plugin

Bây giờ tôi cần mức độ mở rộng và phân tách lõi này cho CMS của tôi được viết và được chuyển đến Go. Về cơ bản tôi có cốt lõi đã hoàn thành bây giờ, nhưng để làm cho nó thật sự linh hoạt, tôi phải có khả năng chèn các sự kiện (móc) và để có các plugin gắn vào các móc này với các chức năng bổ sung.

Tôi không quan tâm về biên dịch lại (động/liên kết tĩnh), miễn là bạn không phải thay đổi cốt lõi để nạp plugin - cốt lõi CMS không bao giờ nên được sửa đổi. (Như WP, Drupal, vv)

tôi nhận thấy có một vài dự án chứ không phải không biết, cố gắng để triển khai sự kiện tại Gò nhìn hơi giống với EventEmitter trong Node.js:

https://github.com/CHH/eventemitter

https://github.com/chuckpreslar/emission

Vì 2 dự án trên không đạt được nhiều sự nổi tiếng và sự chú ý bằng cách nào đó, tôi cảm thấy cách suy nghĩ về các sự kiện này có thể là cách chúng ta nên làm trong Go? Điều này có nghĩa là Go có thể không hướng đến nhiệm vụ này? Để tạo các ứng dụng thực sự mở rộng thông qua các plugin? Không giống như Go có các sự kiện được tích hợp vào lõi của nó, và RPC dường như không phải là một giải pháp hợp lệ để tích hợp các plugin vào ứng dụng cốt lõi của bạn như chúng được xây dựng một cách nguyên bản, và như thể chúng là một phần của chính bản thân ứng dụng.

Cách tốt nhất để tích hợp plugin liền mạch vào ứng dụng cốt lõi của bạn, cho các điểm mở rộng không giới hạn (cốt lõi) mà không cần thao tác lõi mỗi khi bạn cần kết nối một plugin mới?

+1

Xem cơ sở dữ liệu/sql và gói cơ sở dữ liệu/sql/trình điều khiển để biết ví dụ về kiến ​​trúc plugin. Trong kiến ​​trúc này, các trình cắm thêm [đăng ký] (http://godoc.org/database/sql#Register) từ các hàm init() và thực hiện các giao diện như được định nghĩa bởi gói trình điều khiển. –

Trả lời

25

Nói chung, trong Go, nếu bạn cần sự kiện bạn có thể cần phải sử dụng kênh, nhưng nếu bạn cần plugin, cách để đi là giao diện. Dưới đây là một ví dụ dài về kiến ​​trúc plugin đơn giản giúp giảm thiểu mã cần được ghi trong tệp chính của ứng dụng để thêm plugin (điều này có thể được tự động nhưng không phải dnyamic, xem bên dưới).

Tôi hy vọng nó theo hướng bạn đang tìm kiếm.


1. Plugin giao diện

Vì vậy, không sao, chúng ta hãy nói rằng chúng ta có hai plugins, Fooer và người làm. Đầu tiên chúng ta xác định các giao diện của họ:

// All DoerPlugins can do something when you call that method 
type DoerPlugin interface { 
    DoSomething() 
} 

// All FooerPlugins can Foo() when you want them too 
type FooerPlugin interface { 
    Foo() 
} 

2. Plugin Registry

Bây giờ, ứng dụng cốt lõi của chúng tôi có một registry plugin. Tôi đang làm điều gì đó nhanh chóng và bẩn thỉu ở đây, chỉ để có ý tưởng trên:

package plugin_registry 

// These are are registered fooers 
var Fooers = []FooerPlugin{} 

// Thes are our registered doers 
var Doers = []DoerPlugin{} 

Bây giờ chúng tôi vạch trần các phương pháp để thêm plugin vào sổ đăng ký. Cách đơn giản là thêm một loại cho mỗi loại, nhưng bạn có thể đi với các công cụ phản chiếu phức tạp hơn và có một hàm.Nhưng thông thường tại Gò, cố gắng giữ cho mọi thứ đơn giản :)

package plugin_registry 

// Register a FooerPlugin 
func RegisterFooer(f FooerPlugin) { 
    Fooers = append(Fooers, f) 
} 

// Register a DoerPlugin 
func RegisterDoer(d DoerPlugin) { 
    Doers = append(Doers, d) 
} 

3. Triển khai và đăng ký một plugin

Bây giờ, giả sử đây là mô-đun plugin của bạn. Chúng tôi tạo ra một plugin đó là một doer, và trong gói của chúng tôi của init() phương pháp chúng tôi đăng ký nó. init() xảy ra một lần trên chương trình bắt đầu cho mọi gói được nhập.

package myplugin 

import (
    "github.com/myframework/plugin_registry" 
) 
type MyPlugin struct { 
    //whatever 
} 

func (m *MyPlugin)DoSomething() { 
    fmt.Println("Doing something!") 
} 

Một lần nữa, đây là "init kỳ diệu" mà đăng ký gói tự động

func init() { 
    my := &MyPlugin{} 
    plugin_registry.RegisterDoer(my) 
} 

4. Nhập các plugin đăng ký chúng tự động

Và bây giờ, chỉ điều chúng tôi cần thay đổi là những gì chúng tôi nhập vào gói chính của chúng tôi. Kể từ khi Đi không có nhập hoặc nhập liên kết động, đây là điều duy nhất bạn cần phải viết. Thật là tầm thường khi tạo tập lệnh go generate sẽ tạo tệp chính bằng cách xem trong cây tệp hoặc tệp cấu hình và tìm tất cả các plugin bạn cần nhập. Nó không năng động nhưng nó có thể được tự động hóa. Bởi vì chính nhập khẩu các plugin cho các tác dụng phụ của việc đăng ký, nhập khẩu uses the blank identifier to avoid unused import error.

package main 

import (
    "github.com/myframework/plugin_registry" 

    _ "github.com/d00dzzzzz/myplugin" //importing this will automaticall register the plugin 
) 

5. Trong cốt lõi của ứng dụng

Và bây giờ ứng dụng cốt lõi của chúng tôi không cần bất kỳ mã để thay đổi để có thể tương tác với các plugin:

func main() { 


    for _, d := range plugin_registry.Doers { 
     d.DoSomething() 
    } 

    for _, f := range plugin_registry.Fooers { 
     f.Foo() 
    } 

} 

Và đó là về nó. Hãy nhớ rằng plugin đăng ký phải là một gói riêng biệt rằng cả lõi của ứng dụng và các plugin có thể nhập, do đó bạn sẽ không có nhập khẩu vòng tròn.

Tất nhiên bạn có thể thêm trình xử lý sự kiện vào danh sách kết hợp này, nhưng như tôi đã trình bày, không cần thiết.

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