类型 - 子类型关系。有些东西似乎不清楚

时间:2010-02-15 18:18:27

标签: oop liskov-substitution-principle

我正在阅读面向对象编程语言的类的一些幻灯片,并进入类型子类型定义:

Barbara Liskov,“数据抽象和层次结构”,SIGPLAN通知, 23,5,1988年5月:

  

这里需要什么   喜欢以下替代   property:如果对于每个对象o_s   类型S有一个对象o_T   类型T使得对于所有程序P
  用T来定义,行为   当o_S为时,P不变   取代o_T然后S是a   T的子类型

然后是一个例子:

  

Point = {x:整数,y:整数}
     PositivePoint = {x:正面,y:正面}
     其中Positive = {k:Integer | k> 0}

     

我们可以说PositivePoint≤Point吗?

     

是的,因为PositivePoint类型的元素可能总是如此   在中定义的程序中替换Point类型的元素   点条款!

现在......对我而言,它似乎应该完全相反:Point≤DealgePoint,因为我无法在使用带负坐标的Point的程序中使用PositivePoint,而我可以反过来。

我怀疑语法是Type ≤ Sub-type还是Sub-Type ≤ Type,但声明似乎更清楚,那有什么不对呢?


修改

为了让事情变得简单,问题是: 你能说PositivePointPoint的子类型吗? 为什么呢?


第二次编辑

我在这里报告我在评论中所写的内容,希望它能让我的问题更加清晰:

  

假设程序必须绘制一个   来自Point的方形地图(-100,-100)   到Point(100,100)。什么会   如果你使用类型会发生   PositivePoint?该计划是否会   行为不变?它不会。   这种“不变的行为”是唯一的   我得不到的东西。如果定义   子类型只是inheriting and overriding来自另一种类型   没关系,但似乎不是   案件。

4 个答案:

答案 0 :(得分:3)

Liskov是正确的,PositivePoint≤Point,因为PositivePoint是Point的细化。任何使用Point的代码也必须能够使用PositivePoint,因为总是有可能Point的坐标是正的。反之亦然,因为使用PositivePoint的代码可能会假设坐标始终为正,并且将PositivePoint替换为Point会破坏该假设。

请注意,她并不是说PositivePoint可以替换Point,只是可以在需要Point的地方使用PositivePoint。

答案 1 :(得分:1)

您可以通过subsets建模类型关系。

PositivePoint ⊂ PointPositiveInt ⊂ Int的原因相同:正数是所有可能数字的子集!

每个PositivePoint都属于Point,但不是其他方式。

答案 2 :(得分:1)

这个想法是任何接受PositivePoint的函数都依赖于点的值为正的事实。如果传入一个值不为正值的Point,则假设为false,函数将失败。

然而,接受Point的函数不会对该点的正面性做出任何假设,所以如果你传入一个PositivePoint,那就没关系了。

请注意,这仅适用于不可变的Point类。如果您能够更改Point的值,则PositivePoint和Point可能根本没有子类关系,因为对于PositivePoints,操作p.x = -1将失败。

编辑:详细说明:

假设我们有二维数组,它会在需要时自动增长(即,当传递两个正数索引时,你永远不会得到索引越界错误)。现在我们有一个接受PositiveInteger p的函数,然后在索引x,y处访问2d数组。这不会失败,因为x和y保证是正的,2d阵列可以用任何一对正索引索引。但是,如果Point是PositivePoint的子类型,则p实际上可能具有负值,即使它被声明为正值。这意味着使用它来索引数组不再安全。

然而,接受Point的函数不知道该点的值是负还是正 - 它已经必须考虑它们是正的可能性。所以传入一个PositiveInteger不会破坏任何东西。

答案 3 :(得分:0)

我之前没有看到用于表示这个的≤符号,但我认为PositivePoint ≤ Point的含义意味着Point具有比PositivePoint更大的潜在值范围(即:PositivePointPoint的子集,PositivePoint的所有实例都可以由Point的有效实例替换,但不能相反。)