inheritance and polymorphism together in golang, are possible?

huangapple go评论87阅读模式
英文:

inheritance and polymorphism together in golang, are possible?

问题

这个问题来自我需要将一个工作中的C++程序逻辑移植到golang环境中。这只是一个例子,我知道它可能看起来很奇怪,但请考虑其背后的逻辑。如果解释让你感到无聊,请直接看代码,它本身很容易理解。否则,我会尝试解释一下。

概念是我有一个包含通用逻辑方法的基类,但该方法使用了每个派生类需要实现的虚函数。

在Go中,我很容易实现基类方法的继承,但是对于派生类的多态适应却很复杂(对我来说):我无法弄清楚如何复制这个机制。

在Go中,我尝试了以下代码:

type TPolygon struct {
	nside int
}

func (p *TPolygon) Area() float64 {
	return 0
}

func (p *TPolygon) MeanArea() float64 {
	return p.Area() / float64(p.nside)
}

type TSquare struct {
	TPolygon

	side float64
}

func NewSquare(sidelength float64) *TSquare {

	return &TSquare{
		TPolygon: TPolygon{nside: 4},

		side: sidelength,
	}
}

func (s *TSquare) Area() float64 {
	return s.side * s.side
}

type TTriangle struct {
	TPolygon

	base, height float64
}

func NewTriangle(b, h float64) *TTriangle {

	return &TTriangle{
		TPolygon: TPolygon{nside: 3},

		base:   b,
		height: h,
	}
}

func (t *TTriangle) Area() float64 {
	return t.base * t.height / 2
}

square := NewSquare(2.0)
square.MeanArea() // -> 0 from TPolygon.Area()

我找到的唯一实现方式是一个绕过方法,违反了DRY原则,因为需要在每个派生类中重复相同的方法:

func (p *TPolygon) meanArea2(a float64) float64 {
	return a / float64(p.nside)
}
func (s *TSquare) MeanArea2() float64 {
	return s.meanArea2(s.Area())
}
func (t *TTriangle) MeanArea2() float64 {
	return t.meanArea2(t.Area())
}

square.MeanArea2() // -> 1 as expected

而且,如果逻辑变得更加复杂,这种重复的方式并不总是容易和可行的。有人知道在golang中是否可能实现这种架构,以及如何实现吗?或者是否有其他接近的解决方案?

英文:

This question comes form the porting I have to do from a working logic of C++ program, to a golang context.
This is just an example, and i see how wierd it can be, but think about the logic behind it.
If the explanation bores you, go to the code, it is pretty self explanatory.. otherwise I try to explain.
The concept is that I have a base class that contains a method with common logic, but that methot use virtual function that each descendant need to implement.

In go, I easly achieve inheritance of the base method, but the polimorphic adaptation to the descendant it's complicate (for me): I can't figure out how replicate this mechanism..

class TPolygon{

private:
	int nside;

public:
	TPolygon(int n){ nside=n; }
	virtual float Area()=0;
	float MeanArea(){ return Area()/nside; }
};

class TSquare: public TPolygon{

private:
	float side;

public:
	TSquare(float sidelen):TPolygon(4){ side=sidelen; }
	float Area(){ return side*side; }
};

class TTriangle: public TPolygon{

private:
	float base, height;

public:
	TTriangle(float b, float h):TPolygon(3){ base=b; height=h; }
	float Area(){ return base*height/2; }
};

TSquare *square=new TSquare(2.0);
square->MeanArea(); // -> 2*2 / 4 correct

TTriangle *triangle=new TTriangle(5.0, 6.0);
triangle->MeanArea(); // -> 5*6/2 / 3 correct


in go i tried:

type TPolygon struct {
	nside int
}

func (p *TPolygon) Area() float64 {
	return 0
}

func (p *TPolygon) MeanArea() float64 {
	return p.Area() / float64(p.nside)
}

type TSquare struct {
	TPolygon

	side float64
}

func NewSquare(sidelength float64) *TSquare {

	return &TSquare{
		TPolygon: TPolygon{nside: 4},

		side: sidelength,
	}
}

func (s *TSquare) Area() float64 {
	return s.side * s.side
}

type TTriangle struct {
	TPolygon

	base, height float64
}

func NewTriangle(b, h float64) *TTriangle {

	return &TTriangle{
		TPolygon: TPolygon{nside: 3},

		base:   b,
		height: h,
	}
}

func (t *TTriangle) Area() float64 {
	return t.base * t.height / 2
}

square := NewSquare(2.0)
square.MeanArea() // -> 0 from TPolygon.Area()


The only way I found to achieve this, is a workaround that break the DRY principle because need to repeat the same method in each descendant

func (p *TPolygon) meanArea2(a float64) float64 {
	return a / float64(p.nside)
}
func (s *TSquare) MeanArea2() float64 {
	return s.meanArea2(s.Area())
}
func (t *TTriangle) MeanArea2() float64 {
	return t.meanArea2(t.Area())
}

square.MeanArea2() // -> 1 as expected

and moreover, isn't always easy and possible to refactor this way, if the logic get more complicate..
Does anybody knows if this architecture is possible in golang, and how?
Or if there is other workaround that get close?

答案1

得分: 2

有一些方法可以模拟继承,但以下方法更加简洁。它允许计算任何实现了两个方法的类型的面积(Area)和边数(NSides)值:

type MeanAreaSupport interface {
   NSides() int
   Area() float64
}

func MeanArea(shape MeanAreaSupport) float64 {
   return shape.Area()/shape.NSides()
}
英文:

There are ways to emulate inheritance, but the following is much cleaner. It allows calculating the area/nsides value for any type that implements the two methods:

type MeanAreaSupport interface {
   NSides() int
   Area() float64
}

func MeanArea(shape MeanAreaSupport) float64 {
   return shape.Area()/shape.NSides()
}

huangapple
  • 本文由 发表于 2023年2月3日 23:03:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75337511.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定