标签挂多高是门学问;填一次、两边自动更新
这一章讨论定义属性时(第 3 章的第 5、6 步)还需要留心的几个细节,主要是逆属性和属性的默认值。
一个属性的值可能取决于另一个属性的值。 比如,如果一款酒是由某家酒庄生产的,那么这家酒庄就生产这款酒。maker(生产者)和 produces(生产)这两个关系,叫做互为逆关系(inverse relations)。
把信息“两个方向都存一遍”是冗余的。 当我们知道一款酒是由某家酒庄生产的,使用知识库的应用总能推断出逆关系的值——即这家酒庄生产了这款酒。
不过,从知识获取(knowledge-acquisition)的角度看,两个方向的信息都显式可用会更方便:这样用户可以在一个场合填酒,在另一个场合填酒庄,而知识获取系统可以自动补上逆关系的值,从而保证知识库的一致性。
本书的例子有一对逆属性:Wine 类的 maker 属性,和 Winery 类的 produces 属性。当用户创建一个 Wine 类的实例并填上 maker 属性的值时,系统自动把新建的这个实例加进对应 Winery 实例的 produces 属性里。比如,当我们说 Sterling Merlot 是由 Sterling Vineyard 酒庄生产的,系统会把这个酒自动加进 Sterling Vineyard 酒庄所生产的酒的列表里(图 9)。
Winery 类的 produces 属性是 Wine 类的 maker 属性的逆属性。填其中一个属性会触发另一个的自动更新。Sterling Merlot 窗体的 Name 框,指向 Sterling Vineyards 窗体的 Name 框。含义是:当你在酒那边填了“生产者 = Sterling Vineyards”……Sterling Vineyards 窗体的 Produces 列表(第一项 Sterling Merlot 已高亮),指回上面的 Sterling Merlot。含义是:……系统自动把这个酒加进了酒庄的生产清单。很多基于框架的系统允许为属性指定默认值(default value)。 如果某个属性值对某个类的大多数实例都相同,我们就可以把这个值定义为该属性的默认值。之后,每当创建这个类的一个新实例,系统会自动填入这个默认值。我们之后可以把它改成约束所允许的任何其他值。也就是说,默认值是为了方便而存在的:它们不对模型施加任何新的限制,也不以任何方式改变模型。
比如,如果我们要讨论的绝大多数酒都是酒体饱满的,我们可以把 full 设为 body 属性的默认值。那么,除非另有说明,我们定义的所有酒都会是酒体饱满的。
注意,这和“属性值”(slot value)是两回事。 属性值不能改。 比如,我们可以说 Dessert wine 类的 sugar 属性的值是 SWEET。那么 Dessert wine 类的所有子类和实例,sugar 属性的值都会是 SWEET。这个值在任何一个子类或实例里都不能被改掉。
| 默认值(default) | 属性值(slot value) | |
|---|---|---|
| 填不填 | 自动填上 | 自动填上 |
| 能不能改 | 能,随便改 | 不能,改了就是建模错误 |
| 本质 | 一个偷懒用的初始值 | 一条绑死逻辑的约束 |
| 例子 | body 默认 full——博若莱可改成 LIGHT | 甜酒的 sugar = 甜。这不是偏好,是定义 |
body 的默认值 full——大部分酒是饱满的,但博若莱可以改成 LIGHT;Dessert wine 的 sugar = SWEET——甜酒的糖分必须是甜,这不是偏好,是定义。