在Go项目中,我必须定义两种不同的"形状"实现名为MyObject的接口的类型。形状本身是在外部库中定义的类型,并且不实现任何共享接口。
MyObject看起来像
type MyObject interface {
GetShape() *Shape //some unified return value
}
形状看起来像
type Circle struct {
Radius int
X int
Y int
}
type Square struct {
X int
Y int
W int
H int
}
func NewCircle(x int, y int, radius int) Circle
func NewSquare(x int, y int, w int, h int) Square
我有一个实施MyObject的球和一个盒子:
type Ball struct {
shape *Circle
}
type Box struct {
shape *Square
}
func (b *Ball) GetShape() *Shape {
return b.shape
}
func (s *Square) GetShape() *Shape {
return s.shape
}
通过接口这似乎很简单 - 但是我们无法在这种情况下使用它,因为Circle和Square没有实现相同的方法,而且它们不在我们正在工作的包中
对于使用圆形和方形的方法,我需要使用类似
的方法testCircleSquare(circle *Circle, square *Square) bool {}
testSquareSquare(square1 *Square, square2 *Square) bool {}
如何区分或使这两个对象更通用?到目前为止,我唯一的想法是将它们集成到像
这样的类型中type Shape struct {
circle *Circle
square *Square
}
并检查零圈或方形值以确定使用哪个,但如果我添加更多形状,这似乎很难维护。
答案 0 :(得分:2)
@Adrian already explained what's wrong with using interface{}
here
相反,请使用Adapter Pattern。创建自己的Shape界面并为预制形状制作适配器。
Shape接口(它应该被称为Shape2D,因为3D形状表现不同)可能看起来像这样。这为您提供了类型系统的优势,并具有统一的形状界面。
type Shape interface {
Area() float32
Perimeter() float32
X() int
Y() int
}
然后围绕现有对象创建适配器。不需要包装器,您可以为该类型定义别名。 (external
此处表示Circle和Square来自其他一些包。)
type ShapeCircle external.Circle
func (self ShapeCircle) Area() float32 {
return math.Pi * float32(self.Radius) * float32(self.Radius)
}
...and so on...
type ShapeSquare external.Square
func (self ShapeSquare) Area() float32 {
return float32(self.W) * float32(self.H)
}
...and so on...
现在你可以将 Circle&Square对象复制到它们的Shape适配器并将它们用作Shape。
c := external.Circle{ Radius: 10, X: 0, Y: 0 }
shape := ShapeCircle(c)
fmt.Println(shape.Area())
你也可以走另一条路。
external.Function( external.Circle(shape) )
再次,这会创建一个副本。
或者,如果您不喜欢复制,可以在ShapeSquare内的ShapeCircle和Square中嵌入Circle。
type ShapeCircle struct {
external.Circle
}
type ShapeSquare struct {
external.Square
}
然后你可以像以前一样使用ShapeCircle,但你必须给它一个圆圈。可能想要使用New功能来处理它。
c := ShapeCircle{
Circle: external.Circle{ Radius: 10, X: 0, Y: 0 }
}
它可以用作Shape。
fmt.Println(c.Area())
并且c.Circle
可以用作圆圈。无需复制。
external.Function( c.Circle )
答案 1 :(得分:1)
如果你不能为它们构建一个特定的接口,你唯一真正的选择是空接口interface{}
,它可以保存任何值。然后,您必须使用type assertions或reflection对值执行任何有用的操作。从设计的角度来看,这是一个不寻常的案例,因为你持有一个你无法做出任何假设的任意值。