Как заставить полиморфизм пойти на использование дочерних методов? - PullRequest
0 голосов
/ 21 июня 2019

Я исхожу из языка, подобного C ++, где ООП четко определено и обычно используется полиморфизм. Я новичок в использовании Go и пытаюсь вызвать дочерний метод из полиморфизма, и я понятия не имею, что такое правильный шаблон.

Я создал две структуры, как вы увидите, и я определил 2 метода fun1 и fun2, где в базовой структуре я переопределяю только один из них, а в родительском я его вызываю. Если полиморфизм правильный, этот дочерний метод должен быть вызван, и, по крайней мере, в моем примере этого не происходит

Вот код:

package main

import (
    "fmt"
)

type A struct {

}

type B struct {
    A
}

func (a* A) fun1() {
    fmt.Println("I'm in A.fun1()")
    a.fun2()
}

func (a* A) fun2() {
    fmt.Println("I'm in A.fun2()")
}


func (b* B) fun2() {
    fmt.Println("I'm in B.fun2()")
}

func main() {
    b := B{}
    b.fun1()    
}

Вы можете попробовать это здесь: https://play.golang.org/p/s7xZun-6Otx

Вывод был

I'm in A.fun1()
I'm in A.fun2()

и я ожидал

I'm in A.fun1()
I'm in B.fun2()

Как я могу это сделать? какой правильный способ иметь хороший дизайн в Go для этого?

Привет

1 Ответ

1 голос
/ 21 июня 2019

Объекты Go обычно строятся вокруг композиции, а не наследования, поскольку используемый вами шаблон очень затруднит для структуры A возможность делать какие-либо предположения о том, что делает fun2.Полиморфизм в го делается на уровне интерфейса.Предпочтительный метод заключается в переносе «переопределяемой» функциональности fun2 в отдельный тип интерфейса, который передается в функцию fun1 или сохраняется в объекте, содержащем fun1.Без специфики того, как вы будете это делать, трудно сделать разумный пример, но это шаблон:

package main

import (
    "fmt"
)

type fun2er interface {
    fun2()
}

type A struct {
    B fun2er
}

func (a* A) fun1() {
    fmt.Println("I'm in A.fun1()")
    a.B.fun2()
}

type B1 struct {}

func (b B1) fun2() {
    fmt.Println("I'm in B1.fun2()")
}

type B2 struct {}

func (b B2) fun2() {
    fmt.Println("I'm in B2.fun2()")
}

func main() {
    a1 := A{B: B1{}}
    a2 := A{B: B2{}}

    a1.fun1()
    a2.fun1()
}

Это напечатает:

I'm in A.fun1()
I'm in B1.fun2()
I'm in A.fun1()
I'm in B2.fun2()

Редактировать:

Я хотел бы добавить немного больше цвета о том, как это работает под капотом.То, как вы «расширяете» свой тип A с помощью B, называется структурным внедрением и в основном является синтаксическим сахаром для добавления поля к B типа A, названного так же, как его тип:

type A struct {}

type B struct {
    A A
}

Основное отличие состоит в том, что при использовании встраивания структуры вы можете вызывать A методы непосредственно для B объекта b.fun1().Когда это вызывается, параметр this, подобный a, который передается в fun1, - это не весь объект B, а просто поле A внутри него (как если бы вы вызывали b.A.fun1()), котороепочему, когда fun1 вызывает fun2, он вызывает реализацию A, поскольку у него нет доступа к объекту B, в котором он хранится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...