英文:
How to DRY in the following?
问题
具有添加的getName()
函数的典型示例。
我想知道如何不为circle
和rect
编写两次getName()
?
package main
import "fmt"
import "math"
// 这是一个基本的几何形状接口。
type geometry interface {
area() float64
perim() float64
getName() string
}
// 对于我们的示例,我们将在`rect`和`circle`类型上实现此接口。
type rect struct {
width, height float64
name string
}
type circle struct {
radius float64
name string
}
// 要在Go中实现接口,我们只需要实现接口中的所有方法。在这里,我们在`rect`上实现了`geometry`。
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}
func (r rect) getName() string {
return r.name
}
// `circle`的实现。
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perim() float64 {
return 2 * math.Pi * c.radius
}
func (c circle) getName() string {
return c.name
}
// 如果一个变量具有接口类型,那么我们可以调用接口中的方法。这是一个通用的`measure`函数,利用这一点可以处理任何`geometry`。
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
fmt.Println(g.getName())
}
func main() {
r := rect{width: 3, height: 4, name: "rect5"}
c := circle{radius: 5, name: "circle2"}
// `circle`和`rect`结构类型都实现了`geometry`接口,因此我们可以将这些结构的实例用作`measure`的参数。
measure(r)
measure(c)
}
英文:
Typical example with added getName()
function.
I wonder how can I do not write getName()
for circle
and rect
twice?
package main
import "fmt"
import "math"
// Here's a basic interface for geometric shapes.
type geometry interface {
area() float64
perim() float64
getName() string
}
// For our example we'll implement this interface on
// `rect` and `circle` types.
type rect struct {
width, height float64
name string
}
type circle struct {
radius float64
name string
}
// To implement an interface in Go, we just need to
// implement all the methods in the interface. Here we
// implement `geometry` on `rect`s.
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}
func (r rect) getName() string {
return r.name
}
// The implementation for `circle`s.
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perim() float64 {
return 2 * math.Pi * c.radius
}
func (c circle) getName() string {
return c.name
}
// If a variable has an interface type, then we can call
// methods that are in the named interface. Here's a
// generic `measure` function taking advantage of this
// to work on any `geometry`.
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
fmt.Println(g.getName())
}
func main() {
r := rect{width: 3, height: 4, name: "rect5"}
c := circle{radius: 5, name: "circle2"}
// The `circle` and `rect` struct types both
// implement the `geometry` interface so we can use
// instances of
// these structs as arguments to `measure`.
measure(r)
measure(c)
}
答案1
得分: 1
你可以 - 也可能应该 - 将几何类型嵌入到另一个包含名称的结构类型中。除非名称是"circle"或"square"等,否则名称实际上与几何本身没有任何关系。所以你可以这样做:
type namedGeometry struct {
geometry
name string
}
func (ng *namedGeometry) getName() string {
return ng.name
}
这样可以达到相同的目的,保持DRY(不重复原则),并保持关注点的分离。通过嵌入geometry
,你仍然可以在namedGeometry
实例上调用geometry
的方法。
英文:
You could - and potentially should - embed your geometry type in another struct type that includes the name. Unless the name is "circle" or "square" or what have you, the name isn't actually related in any way to the geometry itself. So you could have:
type namedGeometry struct {
geometry
name string
}
func (ng *namedGeometry) getName() string {
return ng.name
}
Which would serve the same purpose, remain DRY, and maintain separation of concerns. With geometry
embedded, you can still call the geometry
methods on a namedGeometry
instance.
答案2
得分: 0
我会采用与Adrian类似的方法,但我会将一个包含公共功能的基本类型嵌入到其他类型中,例如:
type baseShape struct {
name string
}
func (s *baseShape) getName() string {
return s.name
}
type rect struct {
width, height float64
baseShape
}
type circle struct {
radius float64
baseShape
}
这样做之后,你只需要根据每种形状的不同实现相应的函数即可。
英文:
I would take a similar approach to Adrian's, but I would instead embed a base type, which holds common functionality, in your other types e.g.
type baseShape struct {
name string
}
func (s *baseShape) getName() string {
return s.name
}
type rect struct {
width, height float64
baseShape
}
type circle struct {
radius float64
baseShape
}
After doing this, you only need to implement the functions that differ between the shapes on a per type basis.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论