`
varsoft
  • 浏览: 2506498 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

如何应用设计模式设计你的足球引擎(第三、四部分)完

阅读更多

原文地址:http://www.codeproject.com/KB/cpp/applyingpatterns2.aspx

作者:An 'OOP' Madhusudanan

译者:赖勇浩(http://blog.csdn.net/lanphaday


解决方案架构师:你的进度怎么样?

愚蠢的开发者:是的,我觉得我学会了如何应用 Observer 模式去解决所有问题

解决方案架构师:一个模式解决所有问题?

愚蠢的开发者:啊,还不够么?

介绍

关于本文

本文是这个系列的第二篇文章,在阅读本文之前,你应该已经读过并且理解这个系列的第一篇,题为

  • 学习如何应用设计模式设计你的足球引擎(第一、二部分)

在第一篇文章中,我们讨论了

  • 什么是模式,如何使用它们
  • 如何支持方案应用模式
  • 如何用观察者模式来解决我们的足球引擎的设计问题

本文是前一篇文章的延续,在这里我们将讨论

  • 第三部分:应用 Strategy 模式解决“球队(Team)”和“球队策略(TeamStrategy)”相关的设计问题
  • 第四部分:应用 Decorator 模式来解决“球员(Player)”相关的设计问题

如果你已经不记得这些设计问题,最好翻回第一篇文章去看看再回来继续。


第三部分

应用 Strategy 模式

在这一节我们将深入策略模式,然后我们应用这个模式来解决第二个设计问题。像前一篇文章那样,在这里我们再来回顾一下我们的第二个设计问题。

如何你能够记起,我们的第二个设计问题是:

  • 特定的设计问题:在比赛进行时,终端用户能够改变它的球队的策略(如从进攻改为防守)
  • 问题泛化:需要客户端(在这里就是球队)使用的算法(球队策略)能够独立改变

如前文所言,当比赛进行时,我们需要改变球队的策略(如从进攻改为防守)。确切来说就是需要从球队分享球队的策略。

我们已知可以利用策略模式来解决上述设计问题,因为它可使客户端(例如球队)使用的算法(例如球队策略)能够独立改变;那么我们来看看如何利用 Strategy 模式来解决这个设计问题。

理解 Strategy 模式

Strategy 模式非常简单,下面是 Strategy 模式的 UML 图:

clip_image002

Fig - Strategy Pattern

它包括如何几个部分

  • 策略(Strategy

这是一个算法(策略)的抽象类,所有的具体的算法都派生自它。简单地说,它为所有的具体算法(或具体的策略)提供了一个通用的接口。换言之,如果类 Strategy 有个抽象函数叫 foo(),那么所有具体的策略类都应该重载foo() 函数。

  • 具体的策略(ConcreteStrategy

这个类是我们真正实现算法的地方,或者说,它是类 Strategy 的具体实现。例如 Sort 是实现算法的策略类,而具体的策略可以是 MergeSort 或 QuickSort 等等。

  • 上下文(Context

Context可由一个或多个策略类配置,它通常策略接口访问具体策略对象。

应用 Strategy 模式

现在让我们想想如何用 Strategy 模式来解决问题。

clip_image003

Fig - Solving Our Second Design Problem

类 TeamStrategy 包含 Play 函数,AttackStrategy 和 DefendStrategy 是它的具体实现。Team 包含策略,策略可以根据比赛的形势而改变(例如,在领先了若干个进球后从进攻策略改为防守策略)。当用 Team 的PlayGame 函数时,它会调用当前策略的 Play 函数,这一切马上生效,干净利索。

通过策略模式,就可以从类 Team 中分离算法(例如团队的策略)。

Strategy 模式实现

TeamStrategy (Strategy)

下面是类 TeamStrategy 的代码:

  1. 'Strategy:TheTeamStrategyclass
  2. 'Thisclassprovidesanabstractinterface
  3. 'toimplementconcretestrategyalgorithms
  4. PublicMustInheritClassTeamStrategy
  5. 'AlgorithmInterface:Thisistheinterfaceprovided
  6. PublicMustOverrideSubPlay()
  7. EndClass'ENDCLASSDEFINITIONTeamStrategy

AttackStrategy (ConcreteStrategy)

下面是类 AttackStrategy 的代码,它派生自 TeamStrategy:

  1. 'ConcreteStrategy:TheAttackStrategyclass
  2. 'Thisclassisaconcreteimplementationofthe
  3. 'strategyclass.
  4. PublicClassAttackStrategy
  5. InheritsTeamStrategy
  6. 'OverridesthePlayfunction.
  7. 'Letusplaysomeattackinggame
  8. PublicOverridesSubPlay()
  9. 'Algorithmtoattack
  10. System.Console.WriteLine("Playinginattackingmode")
  11. EndSub
  12. EndClass'ENDCLASSDEFINITIONAttackStrategy

DefendStrategy (ConcreteStrategy)

下面是类 DefendStrategy 的代码,它也派生自 TeamStrategy:

  1. 'ConcreteStrategy:TheDefendStrategyclass
  2. 'Thisclassisaconcreteimplementationofthe
  3. 'strategyclass.
  4. PublicClassDefendStrategy
  5. InheritsTeamStrategy
  6. 'OverridesthePlayfunction.
  7. 'Letusgodefensive
  8. PublicOverridesSubPlay()
  9. 'Algorithmtodefend
  10. System.Console.WriteLine("Playingindefensivemode")
  11. EndSub
  12. EndClass'ENDCLASSDEFINITIONDefendStrategy

Team (Context)

下面是类 Team 的代码,根据我们的设计,一个球队在同一时间只能有一种策略:

  1. 'Context:TheTeamclass
  2. 'Thisclassencapsulatesthealgorithm
  3. PublicClassTeam
  4. 'Justavariabletokeepthenameofteam
  5. PrivateteamNameAsString
  6. 'Areferencetothestrategyalgorithmtouse
  7. PrivatestrategyAsTeamStrategy
  8. 'ContextInterfacetosetthestrategy
  9. PublicSubSetStrategy(ByValsAsTeamStrategy)
  10. 'Setthestrategy
  11. strategy=s
  12. EndSub
  13. 'Functiontoplay
  14. PublicSubPlayGame()
  15. 'Printtheteam'sname
  16. System.Console.WriteLine(teamName)
  17. 'Playaccordingtothestrategy
  18. strategy.Play()
  19. EndSub
  20. 'Constructortocreatethisclass,bypassingtheteam's
  21. 'name
  22. PublicSubNew(ByValteamNameAsString)
  23. 'Settheteamnametouselater
  24. Me.teamName=teamName
  25. EndSub
  26. EndClass'ENDCLASSDEFINITIONTeam

组合起来

创建球队,然后设置它们的策略,并开始比赛。下面的代码颇为简单而且有详细的注释。

  1. 'GameEngineclassfordemonstration
  2. PublicClassGameEngine
  3. PublicSharedSubMain()
  4. 'Letuscreateateamandsetitsstrategy,
  5. 'andmaketheteamsplaythegame
  6. 'Createfewstrategies
  7. DimattackAsNewAttackStrategy()
  8. DimdefendAsNewDefendStrategy()
  9. 'Createourteams
  10. DimfranceAsNewTeam("France")
  11. DimitalyAsNewTeam("Italy")
  12. System.Console.WriteLine("Settingthestrategies..")
  13. 'Nowletussetthestrategies
  14. france.SetStrategy(attack)
  15. italy.SetStrategy(defend)
  16. 'Maketheteamsstarttheplay
  17. france.PlayGame()
  18. italy.PlayGame()
  19. System.Console.WriteLine()
  20. System.Console.WriteLine("Changingthestrategies..")
  21. 'Letuschangethestrategies
  22. france.SetStrategy(defend)
  23. italy.SetStrategy(attack)
  24. 'Makethemplayagain
  25. france.PlayGame()
  26. italy.PlayGame()
  27. 'Waitforakeypress
  28. System.Console.Read()
  29. EndSub
  30. EndClass

运行

程序运行后的输出如下:

clip_image004


第四部分

应用 Decorator 模式

在这一节我们来讲讲如何应用 Decorator 模式来解决第三个设计问题(如有必要可参考前一篇文章)。这个问题是与球员的运行时职责指派相关的(如前锋、后卫等)。

你可以考虑创建一个球员类,然后基于它派生出类似前锋、中锋和后卫等多个子类。但它并非最好的解决方案,正如我们之前讨论的——一个球员可以在某个时刻是前锋,另一个时刻又变成了中锋。至少,在我们的足球引擎中是这样的,所以这是我们的设计问题。

特定的设计问题:球员拥有额外的职责,如前锋、后卫等,而且可以在运行时切换。

问题泛化:在不使用子类化的情况下,需要能够动态地为对象(在这里是指球员)挂接额外的职责(如前锋、中锋等)。

理解 Decorator 模式

Decorator 模式可以动态地为对象增加职责,是子类化之外的完美之选。下面是 Decorator 模式的 UML 图:

clip_image005

Fig - Decorator Pattern

这个模式由以下部分组成

  • 组件(Component

类 Component 为组件声明了一个抽象接口,我们能够在这些组件上挂接额外的职责。

  • 具体的组件(ConcreteComponent

类 ConcreteComponent 是类 Component 的具体实现,它真正定义了一个能够挂接的额外职责。

  • 装饰者(Decorator

类 Decorator 从类 Component 继承而来,这意味着它继承了组件的所有接口(函数、属性等),而且持有一个从组件类继承下来的对象的引用。其实一个具体的装饰者甚至能够持有其它装饰者的引用(因为类 Decorator 本来就是由类 Component 派生而来)。

  • 具体的装饰者(Concrete Decorator

这个类是真正为组件挂接职责的地方。

应用 Decorator 模式

现在看看如何应用 Decorator 模式来解决与球员相关的设计问题。

clip_image006

Fig - Solving Our Third Design Problem

可以看到从类 Player 继承两个具体的组件——GoalKeeper 和FieldPlayer,另外还有三个具体的装饰者——Forward、MidFielder和Defender。一个球队有 11 个全场球员和一个守门员(译注:作者写错了,应该是 10个全场球员,后文相同的错误不再指出)。我们的设计问题是需要在运行时指派类似前锋、后卫之类的职责给球员。虽然我们只有 11 全场球员,但可能同时有 11 个前锋和 11 个中锋,因为一个球员可以同时既是前锋又是中锋。通过给球员指派多个角色,和交换它们的角色等,使我们能够规划极佳的比赛策略。

例如可以在比赛的某一时刻通过暂时给一个球员指派 Forward 装饰者,使他可以冲刺和射门。

为具体的组件增加额外的职责,首先可以创建一个具体的组件,然后以引用的形式把它指派给装饰者。比如你可以创建一个全场球员,和一个中锋装饰者,将全场球员指派给中锋装饰者可以为它增加中锋的职责。最后,如果你想,你也可以把同一个球员指派给前锋装饰者。在示例代码中的 GameEngine 模块很好地解释了 Decorator 模式。

下面来看看它的实现,代码都加上了很多注释。

Decorator 模式实现

Player (Component)

类 Player 的实现如下:

  1. 'Component:ThePlayerclass
  2. PublicMustInheritClassPlayer
  3. 'Justgiveanameforthisplayer
  4. PrivatemyNameAsString
  5. 'Thepropertytoget/setthename
  6. PublicPropertyName()AsString
  7. Get
  8. ReturnmyName
  9. EndGet
  10. Set(ByValValueAsString)
  11. myName=Value
  12. EndSet
  13. EndProperty
  14. 'ThisistheOperationinthecomponent
  15. 'andthiswillbeoverridedbyconcretecomponents
  16. PublicMustOverrideSubPassBall()
  17. EndClass'ENDCLASSDEFINITIONPlayer

FieldPlayer (ConcreteComponent)

下面是类 FieldPlayer 的实现:

  1. 'ConcreteComponent:FieldPlayerclass
  2. 'Thisisaconcretecomponent.Later,wewilladdadditionalresponsibilities
  3. 'likeForward,Defenderetctoafieldplayer.
  4. PublicClassFieldPlayer
  5. InheritsPlayer
  6. 'Operation:OverridesPassBalloperation
  7. PublicOverridesSubPassBall()
  8. System.Console.WriteLine("Fieldplayer({0})-passedtheball",_
  9. MyBase.Name)
  10. EndSub
  11. 'Aconstructortoacceptthenameoftheplayer
  12. PublicSubNew(ByValplayerNameAsString)
  13. MyBase.Name=playerName
  14. EndSub
  15. EndClass'ENDCLASSDEFINITIONFieldPlayer

GoalKeeper (ConcreteComponent)

下面是类 GoalKeeper 的实现:

  1. 'ConcreteComponent:GaolKeeperclass
  2. 'Thisisaconcretecomponent.Later,wecanaddadditionalresponsibilities
  3. 'tothisclassifrequired.
  4. PublicClassGoalKeeper
  5. InheritsPlayer
  6. 'Operation:Overridingthebaseclassoperation
  7. PublicOverridesSubPassBall()
  8. System.Console.WriteLine("GoalKeeper({0})-passedtheball",MyBase.Name)
  9. EndSub
  10. 'Aconstructortoacceptthenameoftheplayer
  11. PublicSubNew(ByValplayerNameAsString)
  12. MyBase.Name=playerName
  13. EndSub
  14. EndClass'ENDCLASSDEFINITIONGoalKeeper

PlayerRole (Decorator)

下面是类 PlayerRole 的实现:

  1. 'Decorator:PlayerRoleisthedecorator
  2. PublicClassPlayerRole
  3. Inheritsplayer
  4. 'Thereferencetotheplayer
  5. ProtectedplayerAsplayer
  6. 'Callthebasecomponent'sfunction
  7. PublicOverridesSubPassBall()
  8. player.PassBall()
  9. EndSub
  10. 'Thisfunctionisusedtoassignaplayertothisrole
  11. PublicSubAssignPlayer(ByValpAsplayer)
  12. 'Keepareferencetotheplayer,towhomthis
  13. 'roleisgiven
  14. player=p
  15. EndSub
  16. EndClass'ENDCLASSDEFINITIONPlayerRole

Forward (ConcreteDecorator)

下面是类 Forward 的实现:

  1. 'ConcreteDecorator:ForwardclassisaConcreteimplementation
  2. 'ofthePlayerRole(Decorator)class
  3. PublicClassForward
  4. InheritsPlayerRole
  5. 'AddedBehavior:ThisisaresponsibilityexclusivelyfortheForward
  6. PublicSubShootGoal()
  7. System.Console.WriteLine("Forward({0})-Shootedtheballtogoalpost",_
  8. MyBase.player.Name)
  9. EndSub
  10. EndClass'ENDCLASSDEFINITIONForward

MidFielder (ConcreteDecorator)

下面是类 MidFielder 的实现:

  1. 'ConcreteDecorator:MidFielderclassisaConcreteimplementation
  2. 'ofthePlayerRole(Decorator)class
  3. PublicClassMidFielder
  4. InheritsPlayerRole
  5. 'AddedBehavior:ThisisaresponsibilityexclusivelyfortheMidfielder
  6. '(Don'taskmewhetheronlymidfilderscandribbletheball-atleast
  7. 'itissoinourengine)
  8. PublicSubDribble()
  9. System.Console.WriteLine("Midfielder({0})-dribbledtheball",_
  10. MyBase.player.Name)
  11. EndSub
  12. EndClass'ENDCLASSDEFINITIONMidfielder

Defender (ConcreteDecorator)

下面是类 Defender 的实现:

  1. 'ConcreteDecorator:DefenderclassisaConcreteimplementation
  2. 'ofthePlayerRole(Decorator)class
  3. PublicClassDefender
  4. InheritsPlayerRole
  5. 'AddedBehavior:ThisisaresponsibilityexclusivelyfortheDefender
  6. PublicSubDefend()
  7. System.Console.WriteLine("Defender({0})-defendedtheball",_
  8. MyBase.player.Name)
  9. EndSub
  10. EndClass'ENDCLASSDEFINITIONDefender

组合起来

  1. 'Letusputittogether
  2. PublicClassGameEngine
  3. PublicSharedSubMain()
  4. '--Step1:
  5. 'Createfewplayers(concretecomponents)
  6. 'CreatefewfieldPlayers
  7. DimowenAsNewFieldPlayer("Owen")
  8. DimbeckAsNewFieldPlayer("Beckham")
  9. 'Createagoalkeeper
  10. DimkhanAsNewGoalKeeper("Khan")
  11. '--Step2:
  12. 'Justmakethempasstheball
  13. '(duringawarmupsession;))
  14. System.Console.WriteLine()
  15. System.Console.WriteLine(">WarmupSession...")
  16. owen.PassBall()
  17. beck.PassBall()
  18. khan.PassBall()
  19. '--Step3:Createandassigntheresponsibilities
  20. '(whenthematchstarts)
  21. System.Console.WriteLine()
  22. System.Console.WriteLine(">Matchisstarting..")
  23. 'Setowenasourfirstforward
  24. Dimforward1AsNewForward()
  25. forward1.AssignPlayer(owen)
  26. 'SetBeckhamasourmidfielder
  27. Dimmidfielder1AsNewMidFielder()
  28. midfielder1.AssignPlayer(beck)
  29. 'Now,usetheseplayerstodoactions
  30. 'specifictotheirroles
  31. 'Owencanpasstheball
  32. forward1.PassBall()
  33. 'Andowencanshootaswell
  34. forward1.ShootGoal()
  35. 'Beckhamcanpassball
  36. midfielder1.PassBall()
  37. 'Beckhamcandribbletoo
  38. midfielder1.Dribble()
  39. '[Arrangetheaboveoperationstosomemeaningfullsequence,like
  40. '"Beckhamdribbledandpassedtheballtoowenandowenshootedthe
  41. 'goal;)-justforsomefun]"
  42. '--Step4:Now,changingresponsibilities
  43. '(duringasubstitution)
  44. 'Assumethatowengotinjured,andweneedanewplayer
  45. 'toplayasourforward1
  46. System.Console.WriteLine()
  47. System.Console.WriteLine(">OOps,Owengotinjured."&_
  48. "JerrardreplacedOwen..")
  49. 'Createanewplayer
  50. DimjerrardAsNewFieldPlayer("Jerrard")
  51. 'AskJerrardtoplayinpositionofowen
  52. forward1.AssignPlayer(jerrard)
  53. forward1.ShootGoal()
  54. '--Step5:Addingmultipleresponsibilities
  55. '(Whenaplayerneedtohandlemultipleroles)
  56. 'WealreadyhaveBeckhamasourmidfielder.
  57. 'Letusaskhimtoplayasanadditionalforward
  58. DimonemoreForwardAsNewForward()
  59. onemoreForward.AssignPlayer(beck)
  60. System.Console.WriteLine()
  61. System.Console.WriteLine(">Beckhamhasmultipleresponsibilities..")
  62. 'NowBeckhamcanshoot
  63. onemoreForward.ShootGoal()
  64. 'Andusehisearlierresponsibilitytodribbletoo
  65. midfielder1.Dribble()
  66. 'Accordingtoourdesign,youcanattachtheresponsibilityof
  67. 'aforwardtoagoalkeepertoo,butwhenyouactually
  68. 'playfootball,rememberthatitisdangerous;)
  69. 'Waitforkeypress
  70. System.Console.Read()
  71. EndSub
  72. EndClass

运行

下面是运行程序的输出

clip_image007

结论

在本文中我们讨论了

  • 模式及其实现
  • 模式及其实现

暂时就这么多了。事实上,正是 code project 社区对我前一篇文章的支持才鼓气我的勇气来发表这一篇。谢谢所有人的支持和鼓励!

分享到:
评论

相关推荐

    Android应用源码之体育游戏-疯狂足球源码.zip

    虽然Android本身不提供物理引擎,但开发者可能引入第三方库如Box2D来处理碰撞检测和物理行为。 10. **音频和音效**:游戏中的背景音乐和音效可以增强用户体验。源码可能使用Android的`MediaPlayer`或`SoundPool`类...

    安卓Android源码——体育游戏-疯狂足球源码.rar

    7. **库和依赖**:可能包含第三方库,如游戏引擎组件、网络库、广告库等。 8. **构建脚本**:如Gradle文件,用于构建和打包应用。 9. **测试代码**:单元测试或集成测试代码,确保游戏功能的正确性。 通过研究这个...

    android游戏源码(初学者极力推荐疯狂的足球,一看即懂)

    Android的AudioManager或第三方库可能被用于播放和管理音频资源。 8. **资源管理**: - 图片、音频、动画等资源的加载和释放是优化游戏性能的关键。了解源码如何管理这些资源,如使用AssetManager或Resources类。 ...

    Football:linux足球

    6. **游戏开发框架**: 虽然C语言本身并不包含图形库或游戏引擎,但有许多第三方库可以支持游戏开发,如SDL(Simple DirectMedia Layer)、Allegro或SFML。这些库提供了窗口管理、图像渲染、音频处理等功能,可以帮助...

    FM战术看的下吧

    **第三部分:滑块和管理的模糊** - 滑块是用来调整战术细节的工具,如控球、传球速度等,合理运用可以优化球队表现。 - 管理层面,如训练、球队士气的管理也会影响战术执行的效果。 **第四部分:框架** 1. **心态...

    TT&F战术理论与框架.pdf

    TT&F09是该系列的第六代,起源于对FM06比赛引擎的深入研究,最初是为了测试和反驳关于游戏引擎存在严重问题的观点。随着时间的推移,TT&F不断成熟,增加了更多的战术策略和分析,吸引了大量知识丰富的玩家参与其中...

    Android2.0游戏开发实践宝典源代码(下)

    《Android2.0游戏开发实践宝典源代码(下)》是针对...通过实际操作和调试这些源码,开发者不仅能掌握Android游戏开发的基本技能,还能深入理解游戏开发中的各种设计模式和优化策略,为今后的项目开发打下坚实基础。

    JAVA上百实例源码以及开源项目源代码

    Java 3DMenu 界面源码 5个目标文件 内容索引:Java源码,窗体界面,3DMenu Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都...

    fshows-java-table-football:首展第一届技术部桌上足球比赛分组系统,哈哈

    总的来说,这个项目是一个用Java实现的桌上足球比赛管理系统,涉及到的技术包括但不限于Java编程、MVC设计模式、数据库管理、版本控制(Git)、构建工具(Maven/Gradle)以及前端开发。通过这个项目,开发者不仅可以...

    对外经济贸易大学远程教育学院电子贸易复习大纲.docx

    1. 无纸贸易的运行模式包括点对点模式、单一窗口模式、外联网模式,但不包括一对多模式。无纸贸易通过减少纸质文件的使用,提高交易效率和透明度。 2. 网站设计中,一般建议网站的标准色彩不超过三种,以保持视觉...

    corners-game:进行中

    7. **网络同步**:如果游戏是多人在线模式,那么需要考虑网络同步问题,确保不同玩家之间的操作能够实时同步,这可能涉及到Unity的网络框架或第三方库。 8. **游戏测试与调试**:在开发过程中,使用Unity的内置调试...

    RLForge:火箭联赛的Mods

    UE3是虚幻引擎的第三个主要版本,它引入了许多改进,如高级动态光照、实时全局照明、高级材质系统和蓝光贴图技术。这些特性使得游戏场景更加逼真,同时也为Mod开发者提供了更多的创作可能性。 **Rocket League Mods...

    CSE104-HeadFootball

    虽然JavaScript没有内置的物理引擎,但可以利用自定义的算法或者第三方库如Box2D Lite来模拟物理行为。 五、用户界面与音效 1. 用户界面:游戏的菜单、计分板、游戏状态提示等都是用户界面的一部分,开发者需要使用...

    28家大企业资料

    星巴克不仅推动了咖啡文化的普及,还引领了第三波咖啡浪潮,重视咖啡豆的来源和烘焙技艺。 9. **苹果电脑公司**:苹果是技术创新的代名词,从Mac个人电脑到iPod、iPhone和iPad,苹果产品改变了我们工作、娱乐和沟通...

    5 cool javascript apps

    这款游戏不仅拥有逼真的物理引擎,还提供了多种游戏模式,如单人游戏和多人在线对战等。通过精细的画面设计和优秀的用户体验,Unreal Soccer成为了展示`<canvas>`在游戏开发领域潜力的一个典型例子。 ##### 4. ...

Global site tag (gtag.js) - Google Analytics