I am new to Go and I'm wondering how I can implement a structure similar to abstract classes & methods in Java. In Java, I'd do the following:
abstract class A{
static method1(){
...
method2();
...
}
abstract method2();
}
class B extends A{
method2(){
...
}
}
class C extends A{
method2(){
...
}
}
I know about interfaces and structs. I could build an interface and then a struct to implement method1. But what about method2? I know that I can embed one interface in another and also a struct as a field of another struct. But I don't see a way to implement my structure with those methods.
The only solution I see is to implement method1 both in class B and class C. Isn't there another way?
Note: of course in my case it's not just one method. Also I've got a hierarchy of abstract classes and don't really want to move everything down to the 'subclasses'.
The examples I've found on the internet are mostly with only one method per interface. It would be great if one of you guys could give me a hint here! Thanks.
Since Go does not have static
methods in the OOP sense, you often see those types of methods being implemented as package level functions:
package mypackage
func() Method1() { ... } // Below I will call it Function instead
Such package level functions would then take an interface as an argument. Your code would in that case look something like this:
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)
}
Output:
StructB
You can have composite interfaces, for example from the io package :
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
}
As a side note, don't try to implement java code using go, try to learn the Go Way.
The example you are asking would not compile in Java unless you remove static keyword from method1, so the correct abstract class in Java would like like this.
public abstract class A {
void method1(){
method2();}
abstract void method2();
}
To provide equivalent in go-lang you would have to use an interface in the following way: Go Playground
package main
import (
"fmt"
)
type AI interface {
//define all methods that you want to override
method2()
}
type A struct {//this type is an abstract of AI type since it does not implement method2
AI
}
func (a * A) method1() {
a.method2()
}
type B struct {//inherit all from A
*A
}
func (b *B) method2() {
fmt.Print("Hello from B method1
")
}
func NewB() *B{
b := &B{}
a := &A{b}
b.A = a
return b
}
type C struct {//inherit all from A
*A
}
func (c *C) method2() {
fmt.Print("Hello from C method1
")
}
func NewC() *C{
c := &C{}
a := &A{c}
c.A = a
return c
}
func main() {
b := NewB()
b.method1()
c:= NewC()
c.method1()
}
Since this still not may be easy how to translate/implement java abstract classes/multi-inheritance to go-lang here is the post with comprehensive details. Abstract Class in golang
This is the way I achieved implementing an abstract class the easy way avoiding to run into cyclic references and maintaining good factory patterns.
Let us assume we have the following package structure for our component
component
base
types.go
abstract.go
impl1
impl.go
impl2
impl.go
types.go
factory.go
Define the definition of the component, in this example it will be defined here:
component/types.go
package component
type IComponent interface{
B() int
A() int
Sum() int
Average() int
}
Now let's assume we want to create an abstract class that implements Sum and Average only, but in this abstract implementation we would like to have access to use the values returned by the implemented A and B
To achieve this, we should define another interface for the abstract members of the abstract implementation
component/base/types.go
package base
type IAbstractComponentMembers {
A() int
B() int
}
And then we can proceed to implement the abstract "class"
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
}
And now we proceed to the implementations
component/impl1/impl.go // Asume something similar for 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
}
The reason we use a separate interface for this instead of using the same IComponent interface, is because if we use the same interface in this case, if we import the base package in impl* to use the abstract "class" and also we import the impl* packages in the components package, so the factory can register them, we'll find a circular reference.
So we could have a factory implementation like this
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 LANG OO inherits from Small Talk, not Simula like C++ and not from Java which inherits OO concepts from C++. Remember this and GO OO will sudenly become clear and obvious.
Thus. There is no concept of class in GO. Just objects, sending and receiving messages. GO interface can be conceptually explained as collection of messages.
GO types do not “implement” interfaces they just implement messages that are part of some interface.
Repeat: there is no class, no abstract base class and thus there is no “class based design” in Go (as in Small Talk).
No wonder trying to implement ABC in GO is a mess, as we see here clearly.