模型是某一种业务的抽象,粒度可能很大,也可能很小,相关的业务可能是显而易见的,也可能是隐式的。有些模型是被发现的,而有些模型是被创造的。发现模型的过程是抽象过程,将具体的对象抽象为类或者接口;创造模型的过程是归纳过程,将若干零散的数据归纳在一起,创建一个带有含义的新的类型。
最近在做一个转换程序,将一系列描述动作顺序的数据转换为可视化的图形数据。图形包括泳道(lane),和在泳道中的事件(event),以及事件之间的连接(edge)。表示泳道图元的宽、高、位置,和表示事件的宽、高、位置等都是常量,下面的代码定义了如何生成泳道:
1 2 3 4 5 6 7 8 9 10 11
| { id: item.userName, shape: "lane", width: 200, height: 800, position: { x: 60 + 200 * idx++, y: 20 }, label: item.userName }
|
每一个执行动作的用户生成一个泳道,泳道的宽为200,高为800,泳道横向排列,从x坐标为60开始,y坐标为20,我们首先想到的是将这些数值用常量表示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const lane_width=200 const lane_height=800 const lane_xStart=20 const lane_xStep=200 const lane_y=20 .... { id: item.userName, shape: "lane", width: lane_width, height: lane_height, position: { x: lane_xStart + lane_xStep * idx++, y: lane_y }, label: item.userName }
|
这样改造是建模的第一个步骤,将无意义的数值使用有意义的常量名称代替,这样,代码的可读性提高了,也便于修改。然而,这样做还不够,想象一下,如果需要绘制两组不同的泳道,宽、高和其它位置都有变化,该如何处理呢?这些常量就需要作为变量进行处理。我们需要为这些参数创建一个模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const config = default || { lane: { shape: "lane", width: 200, height: 800, xStart: 60, xStep: 200, y: 20 } } .... { id: item.userName, shape: config.lane.shape, width: config.lane.width, height: config.lane.height, position: { x: config.lane.xStart + config.lane.xStep * idx++, y: config.lane.y }, label: item.userName }
|
现在,如果将default作为传入参数,就可以很方便地修改图元定义了。
进一步研究模型:
1 2 3 4 5 6 7 8
| lane: { shape: "lane", width: 200, height: 800, xStart: 60, xStep: 200, y: 20 }
|
我们发现,x和y是不对称的,x方向有开始和步长,y方向没有,那么如果y方向也有相应的参数,含义是什么呢?应该是泳道可以纵向排列,我们可以修改模型和最终的生成算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const config = default || { lane: { shape: "lane", width: 200, height: 800, xStart: 60, xStep: 200, yStart: 20, yStep: 0 } } .... { id: item.userName, shape: config.lane.shape, width: config.lane.width, height: config.lane.height, position: { x: config.lane.xStart + config.lane.xStep * idx++, y: config.lane.yStart + config.lane.yStep * idx++ }, label: item.userName }
|
在这个例子中,我们将生成模型中的初始化参数抽提出来,创建了一个新的初始参数模型,同时使用这两个模型,可以使代码更容易理解。只通过初始化模型,就可以理解和配置生成模型。