消除方法的重复

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

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()方法。GameObjectHeroGameObject都实现了这个接口,并分别提供了自己的afterUpdate()实现。通过在GameObject中添加一个handler字段,并在Update()方法中调用handler.afterUpdate(),我们可以根据具体的对象类型来调用相应的处理方法。

对于gameObject.SetHandler(gameObject)heroObject.SetHandler(heroObject)的问题,这样做是可以的。因为GameObjectHeroGameObject都实现了IHandler接口,所以它们可以作为自己的处理程序。这样做的好处是,我们可以在GameObjectHeroGameObject之间共享相同的处理逻辑,同时也可以根据需要添加特定于每个对象的处理逻辑。

希望这可以帮助到你!

英文:

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时调用IncSpriteIndexAfterUpdate方法。

希望这对你有帮助!如果你有任何其他问题,请随时问我。

英文:

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++
}

huangapple
  • 本文由 发表于 2014年12月16日 21:09:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/27505413.html
匿名

发表评论

匿名网友

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

确定