蚕茧表示法

蚕茧表示法(Cocoon Notation),简称“蚕茧法”,在设计接口或者写接口文档时是一个有力的工具,精简的描述就能达到准确的定义。
原文参考Github:https://github.com/skyshore2001/cocoon-notation

一种易理解易书写的数据结构表示方法,像抽丝剥茧一样层层剥开一个多层次的像蚕茧一样的复杂对象,常用于数据建模,接口描述,代码注释等。

下面将以实例的方式描述表示规则,并且给出了Javascript和C++两种实现供参考。

对象(object)

也称为结构体(structure)或类(class).

一个对象Customer,有两个字段(或称属性)id和name,则可以表示为

Customer: {id, name}

左侧是类型名(type name),一般用大写字母开头。右侧是类型描述,使用花括号描述对象类型,形式为 {field1, field2, ...}, 括号内是各属性名,以小写字母开头。

Javascript中该对象像这样:

var customer = {id: 100, name: "john"};

而C++中会这样定义结构:

struct Customer 
{
    int id;
    string name;
};

对象中可包含复杂类型的属性,属性名中使用前缀”%”标明结构体或字典,用前缀”@”标明数组,如:

Customer: {id, name, %address, @orders}
Address: {country, city}
Order: {id, total, @lines=[OrderLine]}
OrderLine: {itemId, qty, price}

Customer对象的属性address是一个结构体,用前缀”%”标明;属性orders是一个数组,用前缀”@”标明。
这里属性address和orders没有定义类型名,这意味着类型名与属性名同名,即属性address的类型为Address, 而orders的类型为Orders。
因为类型Orders未定义,但定义了其单数形式Order类型,这隐含着Orders是Order的数组。
如果写完整则应像这样描述:

Customer: {id, name, %address=Address, @orders=[Order]}

将Order放在中括号中,即表示属性orders是Order类型的数组。
Order类型的属性lines描述为

@lines=[OrderLine]

表示它是OrderLine的数组。

属性可以缺省,还可指定缺省值,如:

Address: {country?=CN, city?}

这表示属性country可以没有,如果没有的话则当作值为”CN”。

字典(dictionary)

它是一个集合,其中每一项是一个键值对(key-value pair)。也称哈希表(hash table)或映射表(map)。

使用花括号描述字典,形式为 {key => value},其中value可以是基本类型或复杂类型。
字典类型的命名应使用复数形式,或以”List”, “Map”结尾,如:

Customers: { id => name }

上面定义表示,Customers是一个字典类型,每一项中主键表示id字段,而值表示name字段(基本类型)。

在Javascript中的字典类型像这样:

var customers = {100: "john", 101: "bella"};

注意:虽然与对象类型形式上一样,但含义完全不同。它是对象的集合,名称也是复数形式。

在C++中一般这样定义:

typedef map<int, string> Customers;

字典中每项的值也可以是一个对象,表示为:

Customers: {id=>Customer}
Customer: {id, name}

或可以合并为:

Customers: { id=> {id, name} }

在Javascript中使用:

var customers = {
    100: {id: 100, name: "john"},
    101: {id: 101, name: "bella"}
};

在C++中可以这样定义类型:

struct Customer 
{
    int id;
    string name;
};
typedef map<int, Customer> Customers;

数组(Array)

又称顺序表或列表。

使用中括号描述数组,形式为 [ element ]。命名时应使用复数形式,或以”List”, “Arr”结尾。

要表示一个简单的列表IdList,它的每个元素是一个id,可以表示为

IdList: [id]

Customers是Customer的数组,可以表示为:

Customers: [Customer]
Customer: {id, name}

或合并为:

Customers: [ {id, name} ]

在Javascript中数组类型的变量:

var customers = [ {id: 100, name: "john"}, {id: 101, name: "bella"} ]

在C++中类型常定义为:

struct Customer 
{
    int id;
    string name;
};
typedef vector<Customer> Customers;

如果定义了Customer, 而没有定义复数形式Customers, 则默认Customers是它的数组;反之,如果定义了复数形式Customers/CustomerList/CustomerMap/CustomerArr, 则Customer可以不定义,默认它是前者集合中的值元素。

有时可以用数组替代对象类型,比如Customer有两个元素,第一个是id, 第二个是name, 则可以表示为:

Customer: [id, name]

用数组定义对象时,形式为 [ field1, field2, ... ], 它至少应有两个字段。

在Javascript中的例子:

var customer1 = [100, "john"];
var customer2 = [101, "bella"];

在C++中一般不这样设计,非要用的话也可以用Variant之类的通用类型:

typedef Vector<Variant> Customer; // [id, name]
Customer customer1 = {Variant(100), Variant("john")};

基本类型描述

一个复杂类型最终应分解到它所有的属性,要么是基本类型,要么是已分解到基本类型的复杂类型。

在定义属性时,应通过属性名暗示类型,或通过后缀标识符标明。规则如下:

  • Integer: 后缀标识符为”&”, 或以”Id”, “Cnt”等结尾, 如 customerId, age&
  • Double: 后缀标识符为”#”, 如 avgValue#
  • Currency: 后缀标识符为”@”, 或以”Price”, “Total”, “Qty”, “Amount”结尾, 如 unitPrice, price2@。
  • Datetime/Date/Time: 分别以”Tm”/”Dt”/”Time”结尾,如 tm 可表示日期时间如”2010-1-1 9:00”,comeDt 只表示日期如”2010-1-1”,而 comeTime只表示时间如”9:00”
  • Boolean/TinyInt(1-byte): 以Flag结尾, 或以is开头.
  • String: 未显示指明的一般都作为字符串类型。

在根据设计实现时,应将上述类型对应到所用编程语言所支持的实际类型。

例如以下定义:

Customer: {id, name, age&, score#, balance@, specialPrice, createTm, isNew}

简明地定义了Customer各属性的基本类型,在使用C++定义类型时,可能是这样:

class Money {};

struct Customer
{
    int id;
    string name;
    int age;
    double score;
    Money balance;
    Money specialPrice;
    time_t createTm;
    bool isNew;
};
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值