基于对象模型的代码模板技术与数据表对象模型

基于对象模型的代码模板技术与数据表对象模型

张博

2017.11.01

  1. 小众需求

存在这样一部份工作,单就技术而言并不难,随便找个人就能写,但是相似的工作很多,一个一个写很累人。典型的是对很多数据库表的处理,聪明的办法当然是自动化,根据数据字典分析,然后构造SQL语句,但是有时候这种办法不令人满意,比如不够高效,比如代码晦涩难懂,难以发现错误,难以修改——LocalCache最初正是用这种方法实现的,初次完成当然成就感巨大,然而后续修改却令人抓狂,因此催生了现在这个基于对象模型的代码模板技术。

  1. 这是什么

这是一个用代码模板生成代码的技术,代码模板类似asp或者jsp,通过嵌入的控制代码来生成目标文档。

对象模型是可以自由定义的(C++),代码模板也是任意的,目标文档可以是任何文本,意即,虽然对象模型和处理程序都是C++语言的,但可以用来生成任何文本:C++、Java、SQL甚至纯粹的名单。

不排除未来将对象模型存储在数据库的可能,不过目前,目标用户是程序员。

  1. 第一个示例

这个例子包含一个很简单的对象模型和一个很简单的模板。

对象模型:

table   name  T1

       comment 这是一张表

       columns

              id       long

              name    varchar 32

模板:

//${table.name} ${table.comment}

Struct ${table.name}

{

         <%foreach col in column%>

                   ${col.name} ${col.type};

         <%end%>

}

输出文件:

//T1 这是一张表

Struct T1

{

         Id     long;

         Name  varchar 32;

}

         注意其中的${}部分被替换为对象模型中的对应内容,<%foreach%>则控制对对象模型中的数组做了循环处理。

  1. 对象模型(需要用C++编写)

对象分为三类:

属性——仅仅包含一个值

数组——仅仅包含一个对象数组

对象——包含一组带有名字的对象

 

这是很常见的对象模型,通过对象包含对象可以构建一个无限大的世界。

比如对表格,作为一个对象可以包含这些内容:

         Name 对象是一个属性

         Comment 对象是一个属性

         Columns   对象是一个列的数组

         Indexs       对象是一个索引的数组

而列对象,可以包含这些内容:

         Name 对象是一个属性

         Comment 对象是一个属性

         Type 列的类型可能是一个简单属性也可能是一个对象

  1. 代码模板(嵌入式脚本语言)
    1. 全局对象和栈

全局对象由对象模型构建而来,同时有一个栈用来处理局部对象,foreach和if块内部定义的对象为临时对象,块结束即销毁。

    1. ${}引用对象

${点分隔的对象名}语法引用一个对象并用对象的默认值替换自身所在的位置。

查找对象的顺序符合一般规律。(即先局部后全局)

属性对象的默认值就是属性的值。

对象的默认值是name属性的值。

数组对象不应该在这里出现。

 

如果对象是数组,可以用[下标]引用数组的一个对象,下标从0开始。

    1. <%foreach%>循环控制

<%foreach 变量名 in 对象>

<%end%>

对象必须是数组,对数组的每个对象执行一次

    1. <%if%>分支控制

<%if 对象 exist%>

<%else%>

<endif>

如果对象存在则执行……否则……

此判断只判断对象是否存在,有没有值无关紧要。一般在构建对象模型的时候可以将特殊的属性都生成出来,没必要在代码模板里面做复杂分析。

<%if 对象 equal 对象%>

判断两个对象的默认值是否相等,第二个对象可以使用双引号包裹的字符串。

 

不排除增加数值判断的可能。

    1. <%dim%>定义对象

<%dim 对象名=对象%>

定义对象,用来简化代码,可以使用双引号包裹的字符串。

    1. <%set%>设置对象

<%set 对象名=对象%>

设置对象,可以使用双引号包裹的字符串。

    1. 不常用语法
      1. Foreach的stepto

<%foreach 变量名 stepto 对象%>

<%foreach 变量名 stepto 对象 连接符%>

         此循环的变量名对应的对象不是数组的一个元素,而是从第一个开始到这个的一个新数组,举例比较容易理解:

         对象数组包含三个元素,那么三次循环的对象数组是:

         1

         1,2

         1,2,3

         这种语法可以用于对一个复合索引生成部分查找代码。

        

         循环变量的name是每个元素的默认值的连接。

         可选的连接符用来在生成循环变量的默认值时增加连接符。

      1. 后++

${对象++}可以在使用完对象后将对象的内容加一。某些场合需要递增对象时可用。

  1. 典型案例

LocalCache系统是第一个使用案例,实际上,这个系统就是LocalCache系统的一部分。

LocalCache系统包括若干组基于C++的共享内存结构和完整的JNI操作接口,每组数据包含若干个表,每个表包含若干个索引,每个索引包含若干个列,每个索引都可以做部分搜索。

包括若干个模板文件,代码不到1000行,生成的代码超过2万行。

  1. 数据表对象模型
    1. 对象模型
      1. 根对象

名称

类型

说明

name

属性

总的名称

sys

属性

JNI动态库名称和Java类名称

packaeg

属性

JNI Java包

firstPI

属性

共享内存专用

PII

属性

共享内存专用

tables

数组

一组表对象

      1. 表对象

名称

类型

说明

name

属性

名称

comment

属性

说明

mutex

属性

此属性存在则使用内置互斥

members

数组

一组列

indexs

数组

一组索引

functions

数组

一组附加函数

lists

数组

一组附加列表

      1. 附加列表对象

名称

类型

说明

name

属性

名称

comment

属性

说明

members

数组

一组列(全部列,包含比较列和非比较列)

key_members

数组

一组比较列(即主键)

functions

数组

一组附加函数

      1. 附加函数对象

名称

类型

说明

name

属性

名称

comment

属性

说明

type

属性

函数类型,由代码模板处理

no_index_col

属性

若此属性存在则此函数不涉及索引列,仅用于主数据的附加函数,附加列表一律不允许修改比较列

members

数组

一组列,由代码模板处理

      1. 索引对象

名称

类型

说明

name

属性

名称,第一个索引将用作主键

members

数组

一组列,按照顺序比较,允许部分查找

      1. 列对象

名称

类型

说明

name

属性

名称

comment

属性

说明

type

属性

C++数据类型,包括sstring和不同长度的整数

ParamType

属性

C++参数类型,用作函数参数时使用

JavaType

属性

Java数据类型

…..

属性

其它一些代码中需要根据数据类型使用的属性,提前设置好,避免脚本中判断

    1. 使用对象模型
      1. 示例

      1. 添加表

    CCTModel_table createcode;

    CCTModel_table::table * p;

 

    p = createcode.AddNewTable("Table", "用于测试的表,不可删除", true);

函数:

    table * AddNewTable(char const * name, char const * comment, bool mutex)

参数:

    Name 表的名称,必须符合目标代码语言的规范,如果用于JNI则不能使用下划线

    Comment 注释,能否多行取决于代码模板如何处理

    Mutex 是否内置互斥,内置互斥为支持多进程和多线程的用于表、索引和附加列表的单一写优先读写锁,可以确保索引的一致性,如果有意见可以不使用内置互斥而自行处理互斥。

      1. 添加表的列

    p->AddMember("A", "str", 8, "A字符串");

函数:

    bool AddMember(char const * name, char const *type, long len, char const * comment)

参数:

         Name 列名

         Type 类型,str或int,根据长度不同实现为不同类型

         Len 长度,对于str实现为sstring<len+1 >,对于int则分别实现为long int short char

         Comment 注释

      1. 添加索引

    p->AddIndex("IndexBA", "B,A");

函数:

    bool AddIndex(char const * name, char const *members)

参数:

         Name 索引名称

         Members 索引的列,多个列用逗号分隔

说明:

         必须先添加所有索引,然后才能添加附加函数,因为附加函数要根据索引情况采用不同的修改数据方法,不涉及索引的数据修改可以直接进行,涉及索引的必须同步修改索引。

      1. 添加附加函数

    p->AddFunction("SetXYZ", "set", "X,Y,Z", "更新XYZ");

函数:

    bool AddFunction(char const * name, char const * type, char const *members,char const * comment)

参数:

         Name 函数名称,函数名称在实现中会根据需要扩展,附加表名或其它信息,比如JNI接口需要”Java_包名_类名_”开头。

         Type 附加函数的类型,具体由代码模板解释,比如是累加还是修改。后续章节专门解释。

         Memebers,函数操作的列,具体由代码模板解释。

         Comment注释

      1. 附加列表
        1. 添加附加列表

    CCTModel_table::listdata * list;

    list = p->AddList("L1", "第一个附加列表");

函数:

    listdata * AddList(char const * name, char const * comment)

参数:

         Name 名称

         Comment 注释

        1. 添加附加列表的列

    list->AddMember("L1a", "str", 8, false, "");

函数:

    bool AddMember(char const * name, char const *type, long len, bool iskey, char const * comment)

参数:

         isKey 是否是比较列,附加列表可以是允许重复的也可以是不允许重复的,有相应的函数操作,如果混合了不同类型的函数,可能得到错误的结果。

         其它参数与表的添加列函数相同。

        1. 添加附加列表的附加函数

    list->AddFunction("Add", "add", "X", "累加X");

函数:

    bool AddFunction(char const * name, char const * type, char const *members, char const * comment)

         参数与表的添加附加函数相同,但是,附加列表的附加函数的操作列不允许是比较列。

    1. 标准函数

系统管理类,如创建、删除。

主键操作,如查找、插入、修改、删除。

索引操作,包括遍历、部分查找,部分查找从第一个索引列递增到全部索引列。

    1. 附加函数
      1. set

类型为set的附加函数修改主数据或附加列表数据。

      1. add

类型为add的附加函数累加主数据或附加列表数据。

(完)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值