如何解决循环依赖而不创建新的包?

huangapple go评论79阅读模式
英文:

How to solve circular dependency without creating new package?

问题

在golang中,我想要一个具有全局注册表的插件系统。结构可以简化如下:

/plugins/registry.go
/plugins/plugin1/impl.go

registry.go:

package plugins

import "plugins/plugin1" // required for plugin1.MakePlugin

type IPlugin interface {
  Register() error
}

type Factory func(x int) IPlugin

var registry = []Factory{
  plugin1.MakePlugin,
}

impl.go:

package plugin1

import "plugins" // required for IPlugin

type Plugin struct {
  x int
}

func MakePlugin(x int) plugins.IPlugin {
  return &Plugin{
    x: x,
  }
}

如何在不将IPlugin移动到第三个(例如common)包的情况下解决这个问题?

附注:我以为如果我从MakePlugin返回*Plugin,它将与Factory兼容,但事实并非如此!

英文:

In golang want a plugins system with a global registry. Structure can be simplified as follows:

/plugins/registry.go
/plugins/plugin1/impl.go

registry.go:

package plugins

import "plugins/plugin1" // required for plugin1.MakePlugin

type IPlugin interface {
  Register() error
}

type Factory func(x int) IPlugin

var registry = []Factory{
  plugin1.MakePlugin,
}

impl.go:

package plugin1

import "plugins" // required for IPlugin

type Plugin struct {
  x int
}

func MakePlugin(x int) plugins.IPlugin {
  return &Plugin{
    x: x,
  }
}

How to solve without moving IPlugin to 3rd (e.g common) package?

PS. I thought if i return *Plugin from MakePlugin this will be compatible with Factory, but its not!!!

答案1

得分: 4

如何在不将IPlugin移动到第三方(例如common)包的情况下解决这个问题?

你至少有两个选项:

  1. 将注册移到第三方包(例如main)中。
  2. 当某个其他包导入插件时,让每个插件自行注册。

示例1

package plugins

type IPlugin interface {
  Register() error
}

type Factory func(x int) IPlugin

var registry []Factory

func Register(ff ...Factory) {
    registry = append(registry, ff...)
}
package main

import (
    "plugins"
    "plugins/plugin1"
)

func init() {
    plugins.Register(plugin1.MakePlugin)
}

func main() {
    // ...
}


示例2

package plugins

type IPlugin interface {
  Register() error
}

type Factory func(x int) IPlugin

var registry []Factory

func Register(ff ...Factory) {
    registry = append(registry, ff...)
}
package plugin1

import "plugins" // IPlugin所需

func init() {
    plugins.Register(MakePlugin)
}

type Plugin struct {
  x int
}

func MakePlugin(x int) plugins.IPlugin {
  return &Plugin{
    x: x,
  }
}
package main

import (
    "plugins"
    _ "plugins/plugin1" // 执行init()即注册
)

func main() {
    // ...
}
英文:

"How to solve without moving IPlugin to 3rd (e.g common) package?"

You have at least two options:

  1. move the registration to a 3rd (e.g. main) package.
  2. have each plugin register itself when imported by some other package.

Example #1

package plugins

type IPlugin interface {
  Register() error
}

type Factory func(x int) IPlugin

var registry []Factory

func Register(ff ...Factory) {
    registry = append(registry, ff...)
}
package main

import (
    "plugins"
    "plugins/plugin1"
)

func init() {
    plugins.Register(plugin1. MakePlugin)
}

func main() {
    // ...
}


Example #2

package plugins

type IPlugin interface {
  Register() error
}

type Factory func(x int) IPlugin

var registry []Factory

func Register(ff ...Factory) {
    registry = append(registry, ff...)
}
package plugin1

import "plugins" // required for IPlugin

func init() {
    plugins.Register(MakePlugin)
}

type Plugin struct {
  x int
}

func MakePlugin(x int) plugins.IPlugin {
  return &Plugin{
    x: x,
  }
}
package main

import (
    "plugins"
    _ "plugins/plugin1" // will execute init() i.e. register
)

func main() {
    // ...
}

答案2

得分: 1

尝试将接口与其实现分离到外部的抽象包中。然后,根据依赖注入适配器模式的范例来依赖它们。

英文:

Try to separate the Interfaces from their implementation to external packages that are abstract. Then, depend on them according to the Dependency injection and Adapter pattern paradigms.

huangapple
  • 本文由 发表于 2022年2月2日 19:42:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/70954992.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定