编程便笺:对象的谓项设计
对象的谓项设计是指用对象的本体特性,而不是形式特性来体现和区分对象的方式。通俗地说区分对象的方式是能力而不是出生。在谓项设计中,对象是由基础类生成,而不是由派生类生成,我们会更关注类的特性而不是类的继承关系。常用的描述是对象具有哪一类的特性,而不常说是哪一类的对象。
举个例子,比如对于卡车,在设计时只会定义汽车类型,而不会去定义派生于汽车的卡车类型。作为替代,在汽车中定义卡车特性的谓项。要区分一辆汽车是否是卡车,是看它是否具有卡车的特性,当它有卡车特性时,可以把它归于卡车一类,反之,则认定它不属于卡车。对于既有轿车特性,又有卡车特性的汽车,你可以认定它为皮卡。
另外之所以称为谓项设计,与对象的内存布局有关。在后面的例子可以看出,对于特性项,在设计中采用了不同于与主项(类的字段)的方式。所有不同的特性都通过谓词连接到主项的一个特定字段。这样的设计可以保证谓项的调整和扩展不会影响主项的内存布局,从而提高对象的扩展、调整能力。
对象的继承关系可以很好体现类的结构以及自我标记能力,而采用谓项设计,主要是以下几个原因:
1、在对象设计时,我们总认为所讨论的对象是清晰的。而这样的要求并不都能达到,很多的时候我们对所面对的对象不都是很清晰。
2、对象的分类有时不止一种,有时用一种分类(结构)去体现另一种分类会显得牵强。
3、类缺乏自我描述能力,对于实体如关键字等信息无法在类中自我体现。类与xml存在一定程度的失配,使得编写解析xml意图的程序变得困难。
4、简化对象的设计层次,同时通过个给对象添加private,meta,ruler,buffer等谓项,可以以一种比较自然的方式,提高对象本身的自我表述和表现能力,以及对象间的联结能力,从而使得应用系统更具柔性色彩。
5、对象内存布局的变化会带出对象的版本问题,而继承结构的调整往往伴随着对象内存布局的变化。
6、可以把更多的精力放在业务意图的体现上,而不是花费在对象积木游戏上。
上面列举了使用谓项设计的一些原因和理由,从下面的例子可以看到,这样的设计是以效率和类的自我标志能力降低为代价。所以在实际设计中,还是要根据实际设计要求选择合适的方法。
以下的例子源于编辑器,假定一个段落可以由text、control、shape三种块对象组成,块对象的层次结构如下图所示:

对象结构图
我们把前置的一些处理放在后面说明,直接先预览一下结果,也就是对象的结构以及对象的使用。
对象的代码如下所示:
//定义块类型 class TBlock : TPredWordList { //主项特性 Field(cssIndex, int); Field(text, wchar_t*); Field(breakPage, bool); Field(blockType, int); //定义谓项特性 PredField(position,0, TPosition*); PredField(element, 1, void*); PredField(control, 2, TBlockControl*); PredField(shape, 3, TBlockShape*); public: TBlock(int ty); ~TBlock(void); public: inline int getTextLength(){return text? (int)_tcslen(get_text()):0;} public: //position PredFieldItem(left, position, left, 0,int) PredFieldItem(top, position, top, 0,int) PredFieldItem(right, position, right, 0,int) PredFieldItem(bottom,position, bottom, 0,int) //control PredFieldItem(controlUri, control, controlUri,NULL,wchar_t*) PredFieldItem(controlObject,control, control, NULL,void*) //shape PredFieldItem(shapeUri, shape, shapeUri,NULL,wchar_t*) PredFieldItem(shapeObject,shape, shape, NULL,void*) };
对象主要由主项特性和谓项特性构成,PredFieldItem则提供了对象直接访问谓项特性项的能力。关于TPredWordList在后面说明。
特性项的代码比较简单,对于复杂的特性项也可以定义成谓项结构,特性项的代码如下:
View Code
//定义块特性 struct TPosition { int left; int top; int right; int bottom; TPosition():left(0),top(0),right(0),bottom(0){} TPosition(int _left,int _top,int _right,int _bottom) :left(_left),top(_top),right(_right),bottom(_bottom){} }; //定义块类别 struct TBlockType { const static int nil = 0; const static int text = 1; const static int control = 2; const static int shape = 3; }; //定义控件特性 struct TBlockControl { wchar_t* controlUri; void * control; TBlockControl(); ~TBlockControl(); }; //定义shape特性 struct TBlockShape { wchar_t* shapeUri; void * shape; TBlockShape(); ~TBlockShape(); };
以下是测试代码:
int _tmain(int argc, _TCHAR* argv[]) { //在以下TPosition等谓项特性是外建的,在实际设计时应 //尽可能由主对象创建,有利于对象的扩展和调整。 //text block TBlock block(TBlockType::text); block.put_text(_tcsdup(L"this is text")); printf("text %S\r\n",block.get_text()); //control block TBlock control(TBlockType::control); control.put_text(_tcsdup(L"this is control")); control.put_position(new TPosition(0,0,200,200)); control.put_right(400); control.put_control(new TBlockControl); control.put_controlUri(_tcsdup(L"ximage")); TPosition* pos = control.get_position(); printf("control position:rect(%d,%d,%d,%d)\r\n", pos->left,pos->top,pos->right,pos->bottom); printf("control uri %S\r\n",control.get_controlUri()); //shape block TBlock shape(TBlockType::shape); shape.put_text(_tcsdup(L"this is shape")); shape.put_position(new TPosition(0,0,200,200)); shape.put_shape(new TBlockShape); shape.put_shapeUri(_tcsdup(L"worknode:process")); pos = shape.get_position(); printf("shape position:rect(%d,%d,%d,%d)\r\n", pos->left,pos->top,pos->right,pos->bottom); printf("control class %S\r\n",shape.get_shapeUri()); wait; }
下面来说一说TPredWordList、TPredWordFast等谓项连接器的结构。
TPredWordList采用链表的方式连接谓项,谓项的静态和动态添加都会比较方便,对于谓词的定义可以独立出来,也可以与OWL结合。存在一个查找的过程,效率上会受一定影响,可以考虑添加hited等谓项,缓存最新访问的谓词和数据。
TPredWordFast采用数组的方式,谓词直接定义成数组序号,这样效率的损失会很少,但限制了谓词的定义和谓项的扩展,对于以后的调整会存在兼容性问题。
谓项连接器的更多实现细节,可以查询以下代码,也可以根据自己需要重新设计:
View Code
//定义谓词结构 struct TPred { int pred; TPred* next; void * val; TPred():pred(0),next(NULL),val(NULL) { }; inline static TPred* alloc() { return new TPred; } inline static void free(TPred* p) { delete p; } inline static TPred * makePred(int _pred) { TPred * p = TPred::alloc(); p->pred = _pred; return p; } inline static TPred * makePred(int _pred, TPred * & p) { p = TPred::alloc(); p->pred = _pred; return p; } }; //定义谓词类型 class TPredWordList { public: TPredWordList(void); ~TPredWordList(void); private: TPred * pwordPtr; public: TPred * getPred(int _pred); TPred * ensurePred(int _pred); void * getPredVal(int _pred); void setPredVal(int _pred, void* v); }; TPredWordList::TPredWordList(void):pwordPtr(NULL) { } TPredWordList::~TPredWordList(void) { TPred* p = pwordPtr; while(p) { pwordPtr = p->next; TPred::free(p); p = pwordPtr; } } TPred * TPredWordList::getPred(int _pred) { TPred * p = pwordPtr; while(p) { if(p->pred==_pred) break; p = p->next; } return p; } TPred * TPredWordList::ensurePred(int _pred) { if(!pwordPtr)return TPred::makePred(_pred,pwordPtr); TPred * p = pwordPtr; while(p) { if(p->pred==_pred)return p; if(!p->next) { return TPred::makePred(_pred,p->next); } else p = p->next; } return NULL; } void * TPredWordList::getPredVal(int _pred) { TPred * p = getPred(_pred); return p ? p->val:NULL; } void TPredWordList::setPredVal(int _pred, void* v) { ensurePred(_pred)->val = v; } //定义快速谓词类型 class TPredWordFast { public: inline TPredWordFast(void):pwordPtr(NULL){}; inline ~TPredWordFast(void){delete[] pwordPtr;} private: TPred ** pwordPtr; public: inline void iniTPredWordList(int countPred){ new TPred *[countPred];} inline TPred * getPred(int _pred){return pwordPtr[_pred];}; inline TPred * ensurePred(int _pred){return pwordPtr[_pred];} inline void * getPredVal(int _pred){return pwordPtr[_pred]->val;} inline void setPredVal(int _pred, void* v){pwordPtr[_pred]->val = v;} };
Field、PredField、PredFieldItem等是一些宏,这些宏可以让对象的主体意图更加明确。要写出更完整的谓项框架,需要用到typetraits和mpl的知识,平时用还是简化一些。关于这些宏可以查阅以下代码:
View Code
#define Field(ide,t) private: t ide;\ public: inline t get_##ide(){return ide;} \ public: inline void put_##ide(t v){ide = v;} #define PredField(ide,n,t) private: const static int _pword_##ide = n; \ public: t get_##ide(){return (t)getPredVal(_pword_##ide);} \ public: void put_##ide(t v){setPredVal(_pword_##ide,v);} #define PredFieldItem(ide,fd,item,fault,t) \ t get_##ide(){return get_##fd()?get_##fd()->##item:fault;}\ void put_##ide(t v){ get_##fd()->##item = v;} #define FreeField(ide) if(ide)delete ide; #define ReleaseField(ide,t) if(ide)((t)ide)->Release(); #define FreePredField(ide) if(get_##ide())delete get_##ide(); #define ReleasePredField(ide,t) if(get_##ide())((t)get_##ide())->Release();
完整的代码:
View Code
#include <stdio.h> #include <stdlib.h> #include <tchar.h> #define wait printf("\r\n");printf("Press any key to exit!"); getchar();exit(1); #define Field(ide,t) private: t ide;\ public: inline t get_##ide(){return ide;} \ public: inline void put_##ide(t v){ide = v;} #define PredField(ide,n,t) private: const static int _pword_##ide = n; \ public: t get_##ide(){return (t)getPredVal(_pword_##ide);} \ public: void put_##ide(t v){setPredVal(_pword_##ide,v);} #define PredFieldItem(ide,fd,item,fault,t) \ t get_##ide(){return get_##fd()?get_##fd()->##item:fault;}\ void put_##ide(t v){ get_##fd()->##item = v;} #define FreeField(ide) if(ide)delete ide; #define ReleaseField(ide,t) if(ide)((t)ide)->Release(); #define FreePredField(ide) if(get_##ide())delete get_##ide(); #define ReleasePredField(ide,t) if(get_##ide())((t)get_##ide())->Release(); //定义谓词结构 struct TPred { int pred; TPred* next; void * val; TPred():pred(0),next(NULL),val(NULL) { }; inline static TPred* alloc() { return new TPred; } inline static void free(TPred* p) { delete p; } inline static TPred * makePred(int _pred) { TPred * p = TPred::alloc(); p->pred = _pred; return p; } inline static TPred * makePred(int _pred, TPred * & p) { p = TPred::alloc(); p->pred = _pred; return p; } }; //定义谓词类型 class TPredWordList { public: TPredWordList(void); ~TPredWordList(void); private: TPred * pwordPtr; public: TPred * getPred(int _pred); TPred * ensurePred(int _pred); void * getPredVal(int _pred); void setPredVal(int _pred, void* v); }; TPredWordList::TPredWordList(void):pwordPtr(NULL) { } TPredWordList::~TPredWordList(void) { TPred* p = pwordPtr; while(p) { pwordPtr = p->next; TPred::free(p); p = pwordPtr; } } TPred * TPredWordList::getPred(int _pred) { TPred * p = pwordPtr; while(p) { if(p->pred==_pred) break; p = p->next; } return p; } TPred * TPredWordList::ensurePred(int _pred) { if(!pwordPtr)return TPred::makePred(_pred,pwordPtr); TPred * p = pwordPtr; while(p) { if(p->pred==_pred)return p; if(!p->next) { return TPred::makePred(_pred,p->next); } else p = p->next; } return NULL; } void * TPredWordList::getPredVal(int _pred) { TPred * p = getPred(_pred); return p ? p->val:NULL; } void TPredWordList::setPredVal(int _pred, void* v) { ensurePred(_pred)->val = v; } //定义快速谓词类型 class TPredWordFast { public: inline TPredWordFast(void):pwordPtr(NULL){}; inline ~TPredWordFast(void){delete[] pwordPtr;} private: TPred ** pwordPtr; public: inline void iniTPredWordList(int countPred){ new TPred *[countPred];} inline TPred * getPred(int _pred){return pwordPtr[_pred];}; inline TPred * ensurePred(int _pred){return pwordPtr[_pred];} inline void * getPredVal(int _pred){return pwordPtr[_pred]->val;} inline void setPredVal(int _pred, void* v){pwordPtr[_pred]->val = v;} }; //定义块特性 struct TPosition { int left; int top; int right; int bottom; TPosition():left(0),top(0),right(0),bottom(0){} TPosition(int _left,int _top,int _right,int _bottom) :left(_left),top(_top),right(_right),bottom(_bottom){} }; //定义块类别 struct TBlockType { const static int nil = 0; const static int text = 1; const static int control = 2; const static int shape = 3; }; //定义控件特性 struct TBlockControl { wchar_t* controlUri; void * control; TBlockControl(); ~TBlockControl(); }; //定义shape特性 struct TBlockShape { wchar_t* shapeUri; void * shape; TBlockShape(); ~TBlockShape(); }; //定义块类型 class TBlock : TPredWordList { //主项特性 Field(cssIndex, int); Field(text, wchar_t*); Field(breakPage, bool); Field(blockType, int); //定义谓项特性 PredField(position,0, TPosition*); PredField(element, 1, void*); PredField(control, 2, TBlockControl*); PredField(shape, 3, TBlockShape*); public: TBlock(int ty); ~TBlock(void); public: inline int getTextLength(){return text? (int)_tcslen(get_text()):0;} public: //position PredFieldItem(left, position, left, 0,int) PredFieldItem(top, position, top, 0,int) PredFieldItem(right, position, right, 0,int) PredFieldItem(bottom,position, bottom, 0,int) //control PredFieldItem(controlUri, control, controlUri,NULL,wchar_t*) PredFieldItem(controlObject,control, control, NULL,void*) //shape PredFieldItem(shapeUri, shape, shapeUri,NULL,wchar_t*) PredFieldItem(shapeObject,shape, shape, NULL,void*) }; TBlockControl::TBlockControl():control(NULL),controlUri(NULL) { } TBlockControl::~TBlockControl() { if(controlUri)delete controlUri; //if(control)((Object*)control)->Release(); } TBlockShape::TBlockShape():shapeUri(NULL) { } TBlockShape::~TBlockShape() { if(shapeUri)delete shapeUri; //if(shape)((Object*)shape)->Release(); } TBlock::TBlock(int ty):blockType(ty),cssIndex(-1),text(NULL),breakPage(false) { } TBlock::~TBlock(void) { FreeField(text) FreePredField(position) FreePredField(control) FreePredField(shape) //ReleasePredField(element,Object*) } int _tmain(int argc, _TCHAR* argv[]) { //在以下TPosition等谓项特性是外建的,在实际设计时应 //尽可能由主对象创建,有利于对象的扩展和调整。 //text block TBlock block(TBlockType::text); block.put_text(_tcsdup(L"this is text")); printf("text %S\r\n",block.get_text()); //control block TBlock control(TBlockType::control); control.put_text(_tcsdup(L"this is control")); control.put_position(new TPosition(0,0,200,200)); control.put_right(400); control.put_control(new TBlockControl); control.put_controlUri(_tcsdup(L"ximage")); TPosition* pos = control.get_position(); printf("control position:rect(%d,%d,%d,%d)\r\n", pos->left,pos->top,pos->right,pos->bottom); printf("control uri %S\r\n",control.get_controlUri()); //shape block TBlock shape(TBlockType::shape); shape.put_text(_tcsdup(L"this is shape")); shape.put_position(new TPosition(0,0,200,200)); shape.put_shape(new TBlockShape); shape.put_shapeUri(_tcsdup(L"worknode:process")); pos = shape.get_position(); printf("shape position:rect(%d,%d,%d,%d)\r\n", pos->left,pos->top,pos->right,pos->bottom); printf("control class %S\r\n",shape.get_shapeUri()); wait; }
----继承,一个美丽的意外。

浙公网安备 33010602011771号