英文:
Eliminating the duplication of methods
问题
以下是重构后的代码,消除了重复部分:
package main
import "fmt"
type Point struct {
x, y int
}
///////////////////////
type IHandler interface {
afterUpdate()
}
type GameObject struct {
Point
title string
status int
ticks float32
spriteIndex int
handler IHandler
}
func (g *GameObject) SetHandler(h IHandler) {
g.handler = h
}
func (g *GameObject) Update() {
if g.ticks == 0 {
g.spriteIndex++
if g.handler != nil {
g.handler.afterUpdate()
}
}
}
func (g *GameObject) afterUpdate() {
g.status = 0 // suppose it does something meaningful
fmt.Println("GameObject afterUpdate handler invoked")
}
///////////////////////
type HeroGameObject struct {
GameObject
health float32
}
func (h *HeroGameObject) afterUpdate() {
h.health-- // suppose it does something meaningful but *different*, using its own properties, for example "health"
fmt.Println("HeroGameObject afterUpdate handler invoked")
}
///////////////////////
func main() {
gameObject := &GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "dummy object",
status: 0,
ticks: 0,
spriteIndex: 0,
}
gameObject.SetHandler(gameObject)
heroObject := &HeroGameObject{
GameObject: GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "hero object",
status: 0,
ticks: 0,
spriteIndex: 0,
},
health: 0,
}
heroObject.SetHandler(heroObject)
gameObject.Update()
heroObject.Update()
}
在重构后的代码中,我们引入了一个IHandler
接口,它定义了afterUpdate()
方法。GameObject
和HeroGameObject
都实现了这个接口,并分别提供了自己的afterUpdate()
实现。通过在GameObject
中添加一个handler
字段,并在Update()
方法中调用handler.afterUpdate()
,我们可以根据具体的对象类型来调用相应的处理方法。
对于gameObject.SetHandler(gameObject)
和heroObject.SetHandler(heroObject)
的问题,这样做是可以的。因为GameObject
和HeroGameObject
都实现了IHandler
接口,所以它们可以作为自己的处理程序。这样做的好处是,我们可以在GameObject
和HeroGameObject
之间共享相同的处理逻辑,同时也可以根据需要添加特定于每个对象的处理逻辑。
希望这可以帮助到你!
英文:
Is it possible to refactor the following code to eliminate the duplication?
I want my GameObject implement the logic for "update" task invoking different update handlers (like my "AfterUpdate"). The current version works, but there are two implementations of "Update" and they are equal.
AfterUpdate invoked on GameObject should operate on its properties, AfterUpdate invoked on HeroGameObject should have access to HeroGameObject's properties (like "health" for example).
What can I do better? Thank you.
package main
import "fmt"
type Point struct {
x, y int
}
///////////////////////
type GameObject struct {
Point
title string
status int
ticks float32
spriteIndex int
}
func (g *GameObject) Update() {
if g.ticks == 0 {
g.spriteIndex++
g.AfterUpdate()
}
}
func (g *GameObject) AfterUpdate() {
g.status = 0 //suppose it does something meaningful
fmt.Println("GameObject afterUpdate handler invoked")
}
///////////////////////
type HeroGameObject struct {
GameObject
health float32
}
func (h *HeroGameObject) Update() {
if h.ticks == 0 {
h.spriteIndex++
h.AfterUpdate()
}
}
func (h *HeroGameObject) AfterUpdate() {
h.health-- //suppose it does something meaningful but *different*, using its own properties, for example "health"
fmt.Println("HeroGameObject afterUpdate handler invoked")
}
///////////////////////
func main() {
gameObject := &GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "dummy object",
status: 0,
ticks: 0,
spriteIndex: 0,
}
heroObject := &HeroGameObject{
GameObject: GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "hero object",
status: 0,
ticks: 0,
spriteIndex: 0,
},
health: 0,
}
gameObject.Update()
heroObject.Update()
}
The output:
> GameObject afterUpdate handler invoked
>
> HeroGameObject afterUpdate handler invoked
UPDATED
I've come up with the following solution and I wonder what do you think:
package main
import "fmt"
type Point struct {
x, y int
}
///////////////////////
type IHandler interface {
afterUpdate()
}
type GameObject struct {
Point
title string
status int
ticks float32
spriteIndex int
handler IHandler
}
func (g *GameObject) SetHandler(h IHandler) {
g.handler = h
}
func (g *GameObject) Update() {
if g.ticks == 0 {
g.spriteIndex++
if g.handler != nil {
g.handler.afterUpdate()
}
}
}
//actually it is IHandler specific implementation number one
func (g *GameObject) afterUpdate() {
g.status = 0 //suppose it does something meaningful
fmt.Println("GameObject afterUpdate handler invoked")
}
///////////////////////
type HeroGameObject struct {
GameObject
health float32
}
// note, this method is commented out
/*
func (h *HeroGameObject) Update() {
if h.ticks == 0 {
h.spriteIndex++
h.AfterUpdate()
}
}*/
//actually it is IHandler specific implementation number two
func (h *HeroGameObject) afterUpdate() {
h.health-- //suppose it does something meaningful but *different*, using its own properties, for example "health"
fmt.Println("HeroGameObject afterUpdate handler invoked")
}
///////////////////////
func main() {
gameObject := &GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "dummy object",
status: 0,
ticks: 0,
spriteIndex: 0,
}
gameObject.SetHandler(gameObject) //!
heroObject := &HeroGameObject{
GameObject: GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "hero object",
status: 0,
ticks: 0,
spriteIndex: 0,
},
health: 0,
}
heroObject.SetHandler(heroObject) //!
gameObject.Update()
heroObject.Update()
}
http://play.golang.org/p/GIwOknSSzx
Is it okay to have "gameObject.SetHandler(gameObject)"?
答案1
得分: 5
使用标志函数和基本接口,像这样怎么样?
type BaseGameObject interface {
Ticks() int
IncSpriteIndex()
AfterUpdate()
}
func UpdateGameObject(o BaseGameObject) {
if o.Ticks() == 0 {
o.IncSpriteIndex()
o.AfterUpdate()
}
}
func (o *GameObject) Ticks() int {
return o.ticks
}
func (o *GameObject) IncSpriteIndex() {
o.spriteIndex++
}
请注意,这是一个示例代码片段,其中定义了一个名为BaseGameObject
的接口和一个名为UpdateGameObject
的函数。GameObject
结构体实现了BaseGameObject
接口的方法。UpdateGameObject
函数接受一个实现了BaseGameObject
接口的对象,并在Ticks
方法返回0时调用IncSpriteIndex
和AfterUpdate
方法。
希望这对你有帮助!如果你有任何其他问题,请随时问我。
英文:
How about using flag function and base interface, like this?
type BaseGameObject interface {
Ticks() int
IncSpriteIndex()
AfterUpdate()
}
func UpdateGameObject(o BaseGameObject) {
if o.Ticks() == 0 {
o.IncSpriteIndex()
o.AfterUpdate()
}
}
func (o *GameObject) Ticks() int {
return o.ticks
}
func (o *GameObject) IncSpriteIndex() {
o.spriteIndex++
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论