消除方法的重复

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

Eliminating the duplication of methods

问题

以下是重构后的代码,消除了重复部分:

  1. package main
  2. import "fmt"
  3. type Point struct {
  4. x, y int
  5. }
  6. ///////////////////////
  7. type IHandler interface {
  8. afterUpdate()
  9. }
  10. type GameObject struct {
  11. Point
  12. title string
  13. status int
  14. ticks float32
  15. spriteIndex int
  16. handler IHandler
  17. }
  18. func (g *GameObject) SetHandler(h IHandler) {
  19. g.handler = h
  20. }
  21. func (g *GameObject) Update() {
  22. if g.ticks == 0 {
  23. g.spriteIndex++
  24. if g.handler != nil {
  25. g.handler.afterUpdate()
  26. }
  27. }
  28. }
  29. func (g *GameObject) afterUpdate() {
  30. g.status = 0 // suppose it does something meaningful
  31. fmt.Println("GameObject afterUpdate handler invoked")
  32. }
  33. ///////////////////////
  34. type HeroGameObject struct {
  35. GameObject
  36. health float32
  37. }
  38. func (h *HeroGameObject) afterUpdate() {
  39. h.health-- // suppose it does something meaningful but *different*, using its own properties, for example "health"
  40. fmt.Println("HeroGameObject afterUpdate handler invoked")
  41. }
  42. ///////////////////////
  43. func main() {
  44. gameObject := &GameObject{
  45. Point: Point{
  46. x: 0,
  47. y: 0,
  48. },
  49. title: "dummy object",
  50. status: 0,
  51. ticks: 0,
  52. spriteIndex: 0,
  53. }
  54. gameObject.SetHandler(gameObject)
  55. heroObject := &HeroGameObject{
  56. GameObject: GameObject{
  57. Point: Point{
  58. x: 0,
  59. y: 0,
  60. },
  61. title: "hero object",
  62. status: 0,
  63. ticks: 0,
  64. spriteIndex: 0,
  65. },
  66. health: 0,
  67. }
  68. heroObject.SetHandler(heroObject)
  69. gameObject.Update()
  70. heroObject.Update()
  71. }

在重构后的代码中,我们引入了一个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.

  1. package main
  2. import "fmt"
  3. type Point struct {
  4. x, y int
  5. }
  6. ///////////////////////
  7. type GameObject struct {
  8. Point
  9. title string
  10. status int
  11. ticks float32
  12. spriteIndex int
  13. }
  14. func (g *GameObject) Update() {
  15. if g.ticks == 0 {
  16. g.spriteIndex++
  17. g.AfterUpdate()
  18. }
  19. }
  20. func (g *GameObject) AfterUpdate() {
  21. g.status = 0 //suppose it does something meaningful
  22. fmt.Println("GameObject afterUpdate handler invoked")
  23. }
  24. ///////////////////////
  25. type HeroGameObject struct {
  26. GameObject
  27. health float32
  28. }
  29. func (h *HeroGameObject) Update() {
  30. if h.ticks == 0 {
  31. h.spriteIndex++
  32. h.AfterUpdate()
  33. }
  34. }
  35. func (h *HeroGameObject) AfterUpdate() {
  36. h.health-- //suppose it does something meaningful but *different*, using its own properties, for example "health"
  37. fmt.Println("HeroGameObject afterUpdate handler invoked")
  38. }
  39. ///////////////////////
  40. func main() {
  41. gameObject := &GameObject{
  42. Point: Point{
  43. x: 0,
  44. y: 0,
  45. },
  46. title: "dummy object",
  47. status: 0,
  48. ticks: 0,
  49. spriteIndex: 0,
  50. }
  51. heroObject := &HeroGameObject{
  52. GameObject: GameObject{
  53. Point: Point{
  54. x: 0,
  55. y: 0,
  56. },
  57. title: "hero object",
  58. status: 0,
  59. ticks: 0,
  60. spriteIndex: 0,
  61. },
  62. health: 0,
  63. }
  64. gameObject.Update()
  65. heroObject.Update()
  66. }

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:

  1. package main
  2. import "fmt"
  3. type Point struct {
  4. x, y int
  5. }
  6. ///////////////////////
  7. type IHandler interface {
  8. afterUpdate()
  9. }
  10. type GameObject struct {
  11. Point
  12. title string
  13. status int
  14. ticks float32
  15. spriteIndex int
  16. handler IHandler
  17. }
  18. func (g *GameObject) SetHandler(h IHandler) {
  19. g.handler = h
  20. }
  21. func (g *GameObject) Update() {
  22. if g.ticks == 0 {
  23. g.spriteIndex++
  24. if g.handler != nil {
  25. g.handler.afterUpdate()
  26. }
  27. }
  28. }
  29. //actually it is IHandler specific implementation number one
  30. func (g *GameObject) afterUpdate() {
  31. g.status = 0 //suppose it does something meaningful
  32. fmt.Println("GameObject afterUpdate handler invoked")
  33. }
  34. ///////////////////////
  35. type HeroGameObject struct {
  36. GameObject
  37. health float32
  38. }
  39. // note, this method is commented out
  40. /*
  41. func (h *HeroGameObject) Update() {
  42. if h.ticks == 0 {
  43. h.spriteIndex++
  44. h.AfterUpdate()
  45. }
  46. }*/
  47. //actually it is IHandler specific implementation number two
  48. func (h *HeroGameObject) afterUpdate() {
  49. h.health-- //suppose it does something meaningful but *different*, using its own properties, for example "health"
  50. fmt.Println("HeroGameObject afterUpdate handler invoked")
  51. }
  52. ///////////////////////
  53. func main() {
  54. gameObject := &GameObject{
  55. Point: Point{
  56. x: 0,
  57. y: 0,
  58. },
  59. title: "dummy object",
  60. status: 0,
  61. ticks: 0,
  62. spriteIndex: 0,
  63. }
  64. gameObject.SetHandler(gameObject) //!
  65. heroObject := &HeroGameObject{
  66. GameObject: GameObject{
  67. Point: Point{
  68. x: 0,
  69. y: 0,
  70. },
  71. title: "hero object",
  72. status: 0,
  73. ticks: 0,
  74. spriteIndex: 0,
  75. },
  76. health: 0,
  77. }
  78. heroObject.SetHandler(heroObject) //!
  79. gameObject.Update()
  80. heroObject.Update()
  81. }

http://play.golang.org/p/GIwOknSSzx

Is it okay to have "gameObject.SetHandler(gameObject)"?

答案1

得分: 5

使用标志函数和基本接口,像这样怎么样?

  1. type BaseGameObject interface {
  2. Ticks() int
  3. IncSpriteIndex()
  4. AfterUpdate()
  5. }
  6. func UpdateGameObject(o BaseGameObject) {
  7. if o.Ticks() == 0 {
  8. o.IncSpriteIndex()
  9. o.AfterUpdate()
  10. }
  11. }
  12. func (o *GameObject) Ticks() int {
  13. return o.ticks
  14. }
  15. func (o *GameObject) IncSpriteIndex() {
  16. o.spriteIndex++
  17. }

请注意,这是一个示例代码片段,其中定义了一个名为BaseGameObject的接口和一个名为UpdateGameObject的函数。GameObject结构体实现了BaseGameObject接口的方法。UpdateGameObject函数接受一个实现了BaseGameObject接口的对象,并在Ticks方法返回0时调用IncSpriteIndexAfterUpdate方法。

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

英文:

How about using flag function and base interface, like this?

  1. type BaseGameObject interface {
  2. Ticks() int
  3. IncSpriteIndex()
  4. AfterUpdate()
  5. }
  6. func UpdateGameObject(o BaseGameObject) {
  7. if o.Ticks() == 0 {
  8. o.IncSpriteIndex()
  9. o.AfterUpdate()
  10. }
  11. }
  12. func (o *GameObject) Ticks() int {
  13. return o.ticks
  14. }
  15. func (o *GameObject) IncSpriteIndex() {
  16. o.spriteIndex++
  17. }

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:

确定