//06-6-16
接口分为查询状态类,更改状态类,分清楚点有利于规范代码。
不要将不该暴露的数据写进头文件。
凡是涉及到A对象的状态更新的,交给A来处理。
尽量保持对象接口的简单,接口要精练。
任务分配要具体,A只对象处理于A相关的事情,而且凡是与A对象相关的事情最好都交给A
对象来处理,不要让细节蔓延,以至于最后不能维护,出现代码混乱,对象互相偶合。
//06-6-26
如果一个对象需要从文件加载数据,不要写加载方法在这个类,继承一个新类,写在新类
里。
这样的好处是,你的基础类可以重复利用了!呵呵。与文件相关的东西被隔离出去了。
〈07-2-13,结合工厂模式才最实际,见07-1-17。
//06-7-21
如果一个类的数据太多,最好分别放到不同的结构里面,对他们进行整体的操作,
比如有的数据需要存盘,有的是静态数据,有的是物理数据,有的是图形数据。
// 06-9-28
关于书中的单实体模式的讨论,我有自己的看法。
首先,好处明显,防止了多实体,而且是面向对象。
问题是,如果他需要打开硬件,那么我们可以在返回实体的方法里面进行,这样避免了其
他系统还没正常运行导致本系统开启失败。但是如果我们开启系统的时候需要一堆参数,
怎么办?不能解决问题了。
其次,单实体类的摧毁时机也需要控制,不能在主程序结束后进行,这就要求不能用
static 来解决问题。
这些问题有待讨论,所以使用单实体时头脑要清楚具体的需求,在进行设计。
// 06-11-10
1 命名空间
关于命名空间的问题确实很头痛。接口的命名空间和接口实现的命名空间最好不要相同。否则只要一打开命名空间后,所有的类都暴露了出来,即便我们只使用接口。
另外, 不要在头文件中打开一个命名空间,这样就丧失了命名空间的保护功能。
2 程序的不同状态的转换
从一个状态切换到其他状态必须要求状态间保存彼此的引用。为了减少关联性,可以使用工厂模式。
// 06-11-13
1 奇怪的对象方法调用
如果你有一个类A,他有一个静态方法 fun(), 一般的调用方法是
A::fun (), 这是正规的调用。
今天发现自己居然莫名其妙地写出了另一个形态:A().fun(),运行是好象没有问题。
但是实际上他的工作方式是在栈上构造一个A,然后调用fun(), 超出生命期就摧毁A。
所以,任何试图保存他的引用的行为都是危险的,呵呵,因为他只是个局部变量。
// 06-11-22
1 对于使用接口来设计的灵活性的认识
接口趋向于强化一个标准,所有遵循标准的模块都可以拿来使用。
在那些需要将来用更好的模块来更新的部分,这些部分不仅是数据组织方式,就数据的
具体操作也不一样的地方, 但是他们完成相同的功能的时候,最好用接口。
当然使用接口时必须遵循标准可能带来一些设计的小问题,但是这些问题都可以很好地解决,而且通过解决的途径看,接口似乎带来了更清晰的逻辑。
但是要注意,设计借口的时候不要考虑的过于通用,否则,设计接口所花费的精力远大于接口所带来的好处,得不偿失。
2 关于静态数据与动态数据的分离
在实际的程序中,一个碰撞模型里面装载的是相对静态的数据,这些数据从磁盘装载以后,很少更新,所以需要尽量地重用这些数据。
比如上面的PRCollModel 里面的 array<PRCollFrame> 里面的数据就是相对静态的,这些数据允许类的多个实例共同享有,但是里面的mCurrFrame就是每个实例必须拥有的动态数据,必须分离出去。
看例子:
PRCollModel model;
model.load ("...");
class Man
{
void setCollModel (CollModel* model);
};
Man players[16];
for (int i=0; i<16; i++)
players[i].setCollModel (&model);
这样就节省了大量的空间是不。
如果原来的mCurrFrame依然在PRCollModel 里面的话, 下面的代码就会出问题:
if (players[1].collide(&players[2])==true)
{
....
}
在设计的时候要尽量多考虑哪些是动态数据,哪些是静态数据,这样可以优化结构。
所以,可以这样改进:
class ModelData
{
void load ();
PRCollFrame *getFrame (int i);
}
class PRModel
: CollModel
{
void update (int f, Vector *p, int dir)
{
mCurrFrame->copy(mData->getFrame(f));
mCurrFrame->translate (p);
mCurrFrame->rotate (dir);
}
CollFrame* getCurrFrame ()
{
return mCurrFrame;
}
private:
PRCollFrame mCurrFrame;
ModelData *mData;
}
//06-11-23
1 静态数据与动态数据的分离(续)
很多地方都需要这样的分离,特别是游戏对象方面。所以,有必要设计一个最好的结构
来大范围地应用这个理论。
先分析下,动态数据和静态数据肯定其中的一类要放入一个结构里面,至于这个结构是
放在内部还是外部,要具体分析。如果放在内部的话,外部接口看起来会很简洁,内部
数据封装的很好,但是实际上这样设计会有很多问题需要解决,比如怎样实例化它,怎
样保证他具有扩展性之类。
a, 静态数据放在外面
class AnimData
{
array<Image*> Images;
bool load (FileStream *stream);
}
class Anim
{
void setStaticData (AnimData *d)
private:
static AnimData* mStaticData;
int mCurrFrame;
}
然后我们想扩展他:
class CollAnimData
: AnimData
{
Sound * voice;
bool load (FileStream *f);
}
class CollAnim
: Anim
{
void update ()
{
CollAnimData *data = (CollAnimData*)mStaticData;
if (...)
data.voice->play ();
}
}
2 关于 Animator类的一些说明
本来以为这个类不仅可以分离静态数据,而且可以重用一些播放的算法类代码。
这个类把具体的动画播放算法隔离出来,那么我们可以重用这些算法,而且可以动态切换动画的播放算法,实现不同的播放效果,这的确是对的,但是他并不能简单的分离静态的数据,所以,如果要达到好的重用效果的话,还要另外设计。
3 关于状态和菜单
一个对象可以同时显示几个菜单,但是一个时刻内只有一个状态,所以,有必要引入状态和状态机的概念。