以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 软件工程论坛 』   (http://bbs.xml.org.cn/list.asp?boardid=48)
----  子类化(subclass) 和 子类型化(subtype)的区别[原创,未经作者许可不得转载]  (http://bbs.xml.org.cn/dispbbs.asp?boardid=48&rootid=&id=35417)


--  作者:pennyliang
--  发布时间:7/9/2006 10:43:00 PM

--  子类化(subclass) 和 子类型化(subtype)的区别[原创,未经作者许可不得转载]
subtype具有更加严格的要求,就是父类的任何子类都可以在运行时可无缝的代替父类的工作,子类的接口具有更加相比父类更加强的前置条件,父类的接口在子类中得到继承,并且不得在子类中修改父类方法的签名.子类型化的好处是实现依赖倒置,参见参考读物的Bicycle一图,

subclass主要目的为了更加方便的重用,通常不需要符合Is-a的要求,如果采用组合,那么必须手写大量接口,然后Delegate给这个成员变量,如果父类很大的话,使用组合需要大量的工作量,而采用继承则方便很多,另外通过继承可以访问protected的成员及其方法,这也是组合所不具备的。

综上,再次对subclass和subtype进行了分析,欢迎网友讨论。

附件是参考读物



[此贴子已经被作者于2006-7-10 17:58:43编辑过]

--  作者:jiachong
--  发布时间:7/17/2006 4:02:00 PM

--  
我觉得可以这样理解
subtype表示实质的概念级的继承,往往符合is-a关系
subclass表示结构上的继承(的确是为了复用),不一定符合is-a关系

从这个角度区分subclass和subtype可以得到同样的结果:
父类的任何子类都可以在运行时可无缝的代替父类的工作,那么是subtype(因为符合了概念上的is-a)
=============================================
以上是一般情形,似乎成立

但似乎也有不对的地方
“父类的任何子类都可以在运行时可无缝的代替父类的工作,子类的接口具有更加相比父类更加强的前置条件”

这句话中的后半句是正确的,但由于这个原因导致前半句不对,因为子类有更强的前置条件,因此在有的情况下它的行为不能完全代替父类

例如矩形的子类正方形,符合概念继承,拥有更强的前置条件:要求长宽相等,因此从矩形那里继承的设置长和宽的方法要求两个参数一样,这个限制导致它不能完全顶替父类


--  作者:pennyliang
--  发布时间:7/18/2006 6:57:00 PM

--  
你说的这个例子恰好可以为我所用,正方形不符合is-a的继承矩形的关系,是因为其子类不能代替父类的工作,原因和你说的一样,按照数理逻辑
p->q   和q->~p 不等价,
其次,父类的任何子类都可以在运行时可无缝的代替父类的工作,子类的接口具有更加相比父类更加强的前置条件这两句话是等价的,这样写更加完美。

父类型的任何子类型都可以在运行时可无缝的代替父类型的工作,子类型的接口具有更加相比父类型更加强的前置条件。

似乎是MIT的女博士吧,搞出的liskov替代原则,就是说的这个意思。


--  作者:jiachong
--  发布时间:7/18/2006 7:35:00 PM

--  
既然前置条件更强,那如何“无缝的代替父类型的工作”?

另外抛开编程实现来说,“正方形is-a矩形”好像很难否定啊


--  作者:pennyliang
--  发布时间:7/18/2006 7:54:00 PM

--  
纠正一下,子类的前置条件不强于于父类的前置条件,最多和父类的前置条件一样强。我前面说错了。改正一下。

约束条件,和集合论结合起来看,前置条件可以理解成有效的输入集合的特征函数,比如
A={x|x>1},那么x>1是特征函数,也可以理解成前置条件,前置条件越弱,集合越大,那么父类的有效输入集合包含于父类的有效输入集合。那么凡是将子类代替父类后,可以适用于父类的一切场合。

另外你说的正方型is-a矩形,请参考robert martin的一本经典书,书名中含面向对象。专门阐述了这个问题,正方形的却不是一个矩形,至少在面向对象的角度上看。


--  作者:pennyliang
--  发布时间:7/18/2006 8:08:00 PM

--  
举例来说吧比如这么一个类
class math
{
   long sum(int i,int j) //求整形i和整形j的值,并返回,条件i,j>0
}
class mathderived:math
{
  override long sum(int i,int j);//求整形i和整形j的值,并返回,条件i,j>-100
}
可以看出mathderived完全可以替代父类,其前置条件弱.

关于矩形,正方形问题
class rectangle
{
  rectangle(int i,int j)//i,j大于零的整数
  replace(int i,int j)//用i,j分别代替长,宽,条件i>=j
  
}
class square:rectangle
{
   square(int i):rectangle(i,i)//这里似乎没有问题
   replace(int i,int j)//用i,j分别代替长,宽,条件i=j  该条件明显强于父类.
}

robert martin的例子我想不起来了,也许这个例子能说明问题.


--  作者:pennyliang
--  发布时间:7/18/2006 8:20:00 PM

--  
这个我也经常搞混,现在在整理一下
1)子类型的前置条件不强于父类形的前置条件(通常情况下和父类形前置条件一样)
2)子类型的后置条件不弱于父类型的后置条件
3)子类型的不变式不弱于父类型的不变式

子类型是对父类型的扩展,但保留了父类型的全貌,全部对父类型的假定都适用于子类型.所有面向父类型的编程,都不会对一个实际的子类型表现出行为未定义的情况.也就是依赖倒置的前提,客户面向的是父类型的编程,但任意一个子类型的程序开发者,都要满足父类型的规约,这样依赖于父类型的开发者才能保证任何一个子类型都能很好的完成工作,对于每个子类型来说可能仅仅是算法的区别,可能某个子类型依赖于文件,有的子类型依赖于数据库....这些细节对于客户来说都是未知的.


--  作者:jiachong
--  发布时间:7/19/2006 9:38:00 AM

--  
以下是引用pennyliang在2006-7-18 19:54:00的发言:
纠正一下,子类的前置条件不强于于父类的前置条件,最多和父类的前置条件一样强。我前面说错了。改正一下。

约束条件,和集合论结合起来看,前置条件可以理解成有效的输入集合的特征函数,比如
A={x|x>1},那么x>1是特征函数,也可以理解成前置条件,前置条件越弱,集合越大,那么父类的有效输入集合包含于父类的有效输入集合。那么凡是将子类代替父类后,可以适用于父类的一切场合。

另外你说的正方型is-a矩形,请参考robert martin的一本经典书,书名中含面向对象。专门阐述了这个问题,正方形的却不是一个矩形,至少在面向对象的角度上看。
************************************************************



对于这句话我感觉是不是有点本末倒置了,“正方形是矩形”在认知概念上是绝对成立的,这是本,OO是人们在软件世界中试图模拟人类认知的产物,是末,那么从正方形的现象得出的结论应该是OO中的继承与真正的概念继承并不等价,而且互不包含



W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
109.375ms