我是 Go 的新手,我想知道如何在 Java 中实现类似于抽象类和方法的结构。在 Java 中,我会执行以下操作:
abstract class A{
static method1(){
...
method2();
...
}
abstract method2();
}
class B extends A{
method2(){
...
}
}
class C extends A{
method2(){
...
}
}
我了解接口和结构。我可以构建一个接口,然后构建一个结构来实现 method1。但是方法2呢? 我知道我可以将一个接口嵌入到另一个接口中,也可以将一个结构作为另一个结构的字段。但是我看不到用这些方法来实现我的结构的方法。
我看到的唯一解决方案是在B类和C类中都实现method1。难道没有别的办法吗?
注意:当然在我的情况下,这不仅仅是一种方法。另外我有一个抽象类的层次结构,我真的不想把所有的东西都移到“子类”。
我在网上找到的例子大多是每个接口只有一个方法。如果你们中的一个人可以在这里给我一个提示,那就太好了!谢谢。
你可以有复合接口,例如来自 io 包:
http://golang.org/src/pkg/io/io.go?s=2987:3047#L57
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader
Writer
}
作为旁注,不要尝试使用 go 实现 java 代码,尝试学习 Go Way。
由于 Go 没有 OOP 意义上的
static
方法,您经常会看到这些类型的方法被实现为包级函数:
package mypackage
func() Method1() { ... } // Below I will call it Function instead
这样的包级函数然后将接口作为参数。在这种情况下,您的代码将如下所示:
package main
import "fmt"
type Methoder interface {
Method()
}
func Function(m Methoder) {
m.Method()
}
type StructB struct{}
func (s *StructB) Method() { fmt.Println("StructB") }
type StructC struct{} // You can do some "inheritance" by embedding a base struct
func (s *StructC) Method() { fmt.Println("StructC") }
func main() {
b := &StructB{}
Function(b)
}
输出:
StructB
这就是我实现抽象类的简单方法,避免遇到循环引用并维护良好的工厂模式。
让我们假设我们的组件有以下包结构
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
}
我们为此使用单独的接口而不是使用相同的 IComponent 接口的原因是,如果我们在这种情况下使用相同的接口,如果我们在 impl* 中导入 base 包以使用抽象“类”并且我们在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() })
}
Go 从 Small Talk 中获取其面向对象的概念,而不是像 C++ 这样的 Simula,也不是从 Java 中获取其 OO 概念的 Java。记住这一点,Go 就会突然变得清晰明了。
因此,Go 中没有类的概念。只是对象,发送和接收消息。 Go 的接口在概念上可以解释为消息的集合。
Go 类型不“实现”接口,它们只是实现作为某些接口一部分的消息。
重复:没有类,没有抽象基类,因此 Go 中没有“基于类的设计”(如 Small Talk)。
难怪尝试在 Go 中实现 ABC 是一团糟,正如我们在这里清楚地看到的那样。
我使用这个技巧来实现一些具有通用实现的糖 API:
package main
import (
"fmt"
)
type Api interface {
Sugar()
Impl()
}
// Common sugar API implementation
type CommonSugar struct {
Api
}
func (s CommonSugar) Sugar() {
fmt.Println("Calling Impl in Sugar")
s.Api.Impl()
fmt.Println("Called Impl in Sugar\n")
}
// A implementation
type ImplA struct {
CommonSugar
}
func (a *ImplA) Impl() {
fmt.Println("A Impl")
}
func NewApiA() Api {
impl := &ImplA{}
impl.CommonSugar.Api = impl
return impl
}
// B implementation
type ImplB struct {
CommonSugar
}
func (a *ImplB) Impl() {
fmt.Println("B Impl")
}
func NewApiB() Api {
impl := &ImplB{}
impl.CommonSugar.Api = impl
return impl
}
func main() {
api := NewApiA()
api.Sugar()
api = NewApiB()
api.Sugar()
}
这是程序输出:
Calling Impl in Sugar
A Impl
Called Impl in Sugar
Calling Impl in Sugar
B Impl
Called Impl in Sugar
除非从 method1 中删除 static 关键字,否则您要求的示例不会在 Java 中编译,因此 Java 中正确的抽象类会像这样。
public abstract class A {
void method1(){
method2();}
abstract void method2();
}
要在 go-lang 中提供等效功能,您必须按以下方式使用接口:Go Playground
package main
import (
"fmt"
)
type AI interface {
method2()
}
type A struct {
AI
}
func (a * A) method1() {
a.method2()
}
type B struct {
*A
}
func (b *B) method2() {
fmt.Print("Hello from B method1\n")
}
func NewB() *B{
b := &B{}
a := &A{b}
b.A = a
return b
}
type C struct {
*A
}
func (c *C) method2() {
fmt.Print("Hello from C method1\n")
}
func NewC() *C{
c := &C{}
a := &A{c}
c.A = a
return c
}
func main() {
b := NewB()
b.method1()
c:= NewC()
c.method1()
}
因为这仍然不是一件容易的事,所以如何翻译/实现 java 抽象类/多继承到 go-lang 这里是具有全面细节的帖子。 golang 中的抽象类