编程便笺:对象的谓项设计

    对象的谓项设计是指用对象的本体特性,而不是形式特性来体现和区分对象的方式。通俗地说区分对象的方式是能力而不是出生。在谓项设计中,对象是由基础类生成,而不是由派生类生成,我们会更关注类的特性而不是类的继承关系。常用的描述是对象具有哪一类的特性,而不常说是哪一类的对象。

    举个例子,比如对于卡车,在设计时只会定义汽车类型,而不会去定义派生于汽车的卡车类型。作为替代,在汽车中定义卡车特性的谓项。要区分一辆汽车是否是卡车,是看它是否具有卡车的特性,当它有卡车特性时,可以把它归于卡车一类,反之,则认定它不属于卡车。对于既有轿车特性,又有卡车特性的汽车,你可以认定它为皮卡。

  另外之所以称为谓项设计,与对象的内存布局有关。在后面的例子可以看出,对于特性项,在设计中采用了不同于与主项(类的字段)的方式。所有不同的特性都通过谓词连接到主项的一个特定字段。这样的设计可以保证谓项的调整和扩展不会影响主项的内存布局,从而提高对象的扩展、调整能力。

    对象的继承关系可以很好体现类的结构以及自我标记能力,而采用谓项设计,主要是以下几个原因:
  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;
}

                                                                                                                                                                   ----继承,一个美丽的意外。

 

posted @ 2013-01-03 13:57  走在溪边  阅读(963)  评论(0)    收藏  举报