Be Like Water--程序设计的平衡和取舍
来源:互联网 发布:远洋数据推销什么 编辑:程序博客网 时间:2024/06/02 20:30
起初编程,有的时候想得多有的时候想得少,一路过来,回头看看,大致这几个方面在实际项目中,关系格外重大:
- 运行效率,直接影响产品的质量,算法设计到底层代码和硬件级别去理解程序的运行
- 规模复杂度,在产品上规模之后的第一要素,需要理清关系,使用经典设计来控制复杂度
- 开发效率,总时间总是不够的,局部单个任务做到“完美”在整体上很可能就是不完美了
三个方面关系总体比较暧昧,比如追求运行效率的时候,往往会给复杂度和开发效率带来压力,等等实际项目中三个因素我们要做的就是因地制宜,根据项目的实际情况来选择在总体上的最佳方案。
正如李小龙所言,如水一般,在瓶子一样的项目中,就形成瓶子一样,在茶壶一样的项目中,就茶壶一样。
阅读项目,学习知识和算法,做恰当的实现。
以streaming状态的生命周期管理为例:
我们streaming本身状态是由10多个参数来控制,并且在不同地图不同时段是由EnvironmentManager(EnvMgr)来更新管理的。
但是玩家如果处在一个特别高的视角的时候,就需要扩大streaming的距离,获得一个更广的视角,这个就要override其中3个参数。
那么这个override的策略就可以从运行效率,复杂度和开发效率三个方面来梳理下。
=EnvMgr侧=
有时候“小人物上篮”就是最优解
简单直接版:
struct StreamingOverrideConfig{ float mRange; float mSize; float mFreq;};void EnvMgr::OverrideStreaming(bool enable, StreamingOverrideConfig* v);//then in tickvoid EnvMgr::Update(float delta){//updates...//override if(mFreeCamOverride) { mCofnig.mRange = mFreeCamOverride.mRange; //... }}
这种写法可以说是刚开始编程的人最容易出现的情况,它的优缺点是:
- 非常简单易懂,实现快
- 量少的时候ok,量多的时候,代码就没法看了,而且各种情况之间override的优先级不清,会出很多问题
但是正如它的优点,在量少,早期的时候,它就是一个最优解。
扩展性强的版本
struct StreamingConfigOverrideCmd{public: //这个函数中去override config virtual void Override(StreamingConfig& config)=0; int mPriority;};void EnvMgr::Update(float delta){ //updates ... //override部分 //整理优先级 sort(mOverrideCmds); //处理cmd的override for_each(mOverrideCmds) { cmd->Override(mConfig); }}
这个版本会是相对成熟一些,扩展性强,需要override的直接扩展cmd就好。
优缺点:
- 实现相对慢,没那么直接
- 扩展性好
一般来说,如果override的config数量在三个的时候,代码就比较难看了,就需要考虑这种了。
==各种情况下的选择原则==
所以如果现在系统中未来override config需求不明,甚至基本看起来很少,那么就简单直接秒杀就好,这种情况下上各种设计,就没那么简洁,在项目开发中属于一个偏拖沓的选择了。
反之,如果看到需求有变多的可能,或者实现者看到自己做的这个override已经是第三个了,那么换成cmd模式就是比较好了。
==知易行难的平衡取舍==
前面聊的是,总体原则就是各个方法有自己的特点,需要因地制宜就好,是一个了解起来很直接的东东。
但是实践起来,有两个大的难点:
1,就是要知道各个状态管理的时候,需要考虑那些点,有哪些选择,把问题拆解的mece(mutually exclusive, collectively exhaustive,完全穷尽,相互独立),这个就是要对技术和实际情况有充分的了解。
2,以平和客观的心态来做选择,我们可能因为怕麻烦或者是炫技而做出非最优(而技术上其实我们可以做到)
需要考虑颇多的player状态管理
看起来就是override一个streaming状态,只要player做一个free camera的时候设置就好了。
这里就是我们非常有可能低估的地方,player状态部分往往是游戏的核心模块,状态复杂多变,而且经手的人非常多,这样就对于复杂度的控制要求很高。
我们也看两种选择:
=状态切换时候设置=
也就是我们最常能够想到的
//player 来管理状态void Player::EnableFreeCam(bool v){ if(v!=mIsFreeCam) { mIsFreeCam = v; EnvMgr::GetInstance()->OverrideConfig(v, mFreeCamStrConfig); }}
既简单又直接,写起来也快,效率也是最优。
但是这也是风险颇高的一个,在于:
- 如果状态出错,代价高:streaming状态如果管理错误,我们难以发现,到时候正常游戏的时候,多加载了很多东西,性能下降,规模大了之后,我们不太容易发现,发现了也很难查过来
- player各种复杂,经手人多,要保证player各种退出机制下把free camera状态设对,需要不少功夫(比如突然换关,切人,player直接删除等等非常规退出都要考虑到这一点)
=每帧重置型=
//Playervoid Player::Update(float delta){//udpates...//override every frameEnvMgr::GetInstance()->OverrideConfig(mIsFreeCam, mFreeCamStrConfig);//env mgrvoid EnvMgr::Update(float t){ //execute and clear if(mFreeCamOverride) { //override streaming mFreeCamOverride = false; }}
这种方法优缺点:
- +:player无论以各种状态退出,都可以保证streaming状态的正确管理,非常的简单直接,想出错都难
- -:如果量比较大,或者是一个大型的执行,那么会有效率隐患
后面这个写法一般在程序员看来评价会不高,但是在效率ok,player的状态又非常复杂的情况下是一个最优解,关键就是要了解到player状态会在规模复杂度和人多手杂的情况下会出现什么。
所谓因地制宜,这个“地”的了解可以说就是“行难”中的“难”了。
sum
所以最后看来,并无最优只有最适合,正确的阅读项目,广泛深入的学习,最后方能如水一样,最好的方式贴合项目,最因地制宜的构建开发过程。
- Be Like Water--程序设计的平衡和取舍
- Enumeration和Iterator的取舍
- 【警惕】const和readonly的取舍
- flex中remoteObject和httpservice的取舍
- group by和distinct的取舍
- android popwindow和dialog的取舍
- Ajax和Flash的比较与取舍
- blend关于透明度的弊端和其alphatest的取舍
- Guid 和 Int 作为系统编号的取舍
- Guid 和 Int 作为系统编号的取舍
- 投资理财:租和买的巧妙取舍
- C语言中宏定义和函数的取舍
- C语言中宏定义和函数的取舍
- C语言中宏定义和函数的取舍
- php和java两者的对比与取舍
- 存储过程和触发器的取舍问题(优缺点分析)
- 存储过程和触发器的取舍问题(优缺点分析)
- C语言中宏定义和函数的取舍
- 图片重命名
- React Native常见问题解决 500
- 关于Android的keystore生成和查看keystore
- html页面跳转及参数传递
- 以进销存管理系统为例的SSM框架整合
- Be Like Water--程序设计的平衡和取舍
- Linux关闭防火墙(Centos6.5)
- Spring Data Jpa 配合MongoDB实现持久层对象属性动态增加
- 【Python】Python3 List count()方法
- 好吧,左小波出山了!
- PL0编译语义分析 递归
- java将一个List赋值给另一个List相关问题
- Two Paths HDU
- NOIP 提高组 2003