Go言語で手動オブジェクト指向

仮想関数をインターフェースに書き出して、Self経由で呼び出す方式。

手順は、

  • 構造体とインターフェースを対にして作る
  • それぞれに埋め込みで継承していく
  • コンストラクタ関数で、Selfを伝搬させていく

こんなダサくて効率の悪いことは普通やらないが、GUIフレームワークのようにオブジェクト指向が合うものには、部分的に似たような構造が使われている感じがする。


package main

import (
	"fmt"
)

type IA interface {
	MethodA()
}

type A struct {
	Self IA
}

func (a *A) MethodA() {
	fmt.Println("A.MethodA")
}

func (a *A) CallMethodA() {
	fmt.Println("A.CallMethodA")
	a.Self.MethodA() // Self経由で呼び出す
}

func NewA(self IA) *A {
	a := &A{}
	if self != nil {
		a.Self = self
	} else {
		a.Self = a
	}
	return a
}

type IB interface {
	IA
	MethodB()
}

type B struct {
	*A
	Self  IB
	Super IA
}

func (b *B) MethodA() {
	fmt.Println("B.MethodA")
	b.Super.MethodA()
}

func (b *B) MethodB() {
	fmt.Println("B.MethodB")
}

func NewB(self IB) *B {
	b := &B{}
	if self != nil {
		b.Self = self
	} else {
		b.Self = b
	}
	b.A = NewA(b.Self)
	b.Super = b.A
	return b
}

type IC interface {
	IB
}

type C struct {
	*B
	Self  IC
	Super IB
}

func (c *C) MethodB() {
	fmt.Println("C.MethodB")
}

func NewC(self IC) *C {
	c := &C{}
	if self != nil {
		c.Self = self
	} else {
		c.Self = c
	}
	c.B = NewB(c.Self)
	c.Super = c.B
	return c
}

type ID interface {
	IC
}

type D struct {
	*C
	Self  ID
	Super IC
}

func (d *D) MethodA() {
	fmt.Println("D.MethodA")
	d.Super.MethodA()
}

func NewD(self ID) *D {
	d := &D{}
	if self != nil {
		d.Self = self
	} else {
		d.Self = d
	}
	d.C = NewC(d.Self)
	d.Super = d.C
	return d
}

func main() {
	d := NewD(nil)
	d.MethodA()
	// D.MethodA
	// B.MethodA
	// A.MethodA

	d.CallMethodA()
	// A.CallMethodA
	// D.MethodA
	// B.MethodA
	// A.MethodA

	d.MethodB()
	// C.MethodB
}