如果您不需要工厂,Max Malysh 的解决方案在某些情况下会起作用。然而,Adrian Witas 给出的解决方案可能会导致循环依赖问题。
这是我实现抽象类的简单方法,尊重循环依赖和良好的工厂模式。
假设我们的组件具有以下包结构
component
base
types.go
abstract.go
impl1
impl.go
impl2
impl.go
types.go
factory.go
定义组件的定义,本例将在此处定义:
component/types.go
package component
type IComponent interface{
B() int
A() int
Sum() int
Average() int
}
现在假设我们要创建一个仅实现 Sum 和 Average 的抽象类,但在这个抽象实现中,我们希望能够使用返回的值由实现的 A 和 B
为此,我们应该为抽象实现的抽象成员定义另一个接口
component/base/types.go
package base
type IAbstractComponentMembers {
A() int
B() int
}
然后我们可以继续实现抽象“类”
component/base/abstract.go
package base
type AbstractComponent struct {
IAbstractComponentsMember
}
func (a *AbstractComponent) Sum() int {
return a.A() + a.B()
}
func (a *AbstractComponent) Average() int {
return a.Sum() / 2
}
现在我们继续实现
component/impl1/impl.go // 假设 impl2
类似
package impl1
type ComponentImpl1 struct {
base.AbstractComponent
}
func (c *ComponentImpl1) A() int {
return 2
}
func (c *ComponentImpl1) A() int {
return 4
}
// Here is how we would build this component
func New() *ComponentImpl1 {
impl1 := &ComponentImpl1{}
abs:=&base.AbstractComponent{
IAbstractComponentsMember: impl1,
}
impl1.AbstractComponent = abs
return impl1
}
我们为此使用单独的接口而不是使用 Adrian Witas 示例的原因是,如果我们在这种情况下使用相同的接口,如果我们导入 base impl* 中的 package 来使用抽象“类”,并且我们在 components 包中导入 impl* 包,以便工厂可以注册他们,我们会找到一个循环引用。
所以我们可以有这样的工厂实现
component/factory.go
package component
// Default component implementation to use
const defaultName = "impl1"
var instance *Factory
type Factory struct {
// Map of constructors for the components
ctors map[string]func() IComponent
}
func (f *factory) New() IComponent {
ret, _ := f.Create(defaultName)
return ret
}
func (f *factory) Create(name string) (IComponent, error) {
ctor, ok := f.ctors[name]
if !ok {
return nil, errors.New("component not found")
}
return ctor(), nil
}
func (f *factory) Register(name string, constructor func() IComponent) {
f.ctors[name] = constructor
}
func Factory() *Factory {
if instance == nil {
instance = &factory{ctors: map[string]func() IComponent{}}
}
return instance
}
// Here we register the implementations in the factory
func init() {
Factory().Register("impl1", func() IComponent { return impl1.New() })
Factory().Register("impl2", func() IComponent { return impl2.New() })
}