弊端是,没有人还记得面向对象原本要解决的问题是什么。
1、面向对象原本要解决什么(或者说有什么优良特性)
似乎很简单,但实际又很不简单:面向对象三要素 封装、继承、多态
( 警告 :事实上,从业界如此总结出这面向对象三要素的一刹那开始,就已经开始犯错了!)。
封装 :封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,或者叫 接口 。
有了封装,就可以明确区分 内外 ,使得类实现者可以修改封装 内 的东西而不影响 外 部调用者;而外部调用者也可以知道自己不可以碰哪里。这就提供一个良好的合作基础——或者说,只要 接口 这个基础约定不变,则代码改变不足为虑。
继承+多态 :继承和多态必须一起说。一旦割裂,就说明理解上已经误入歧途了。
先说 继承 :继承同时具有两种含义:其一是继承基类的方法,并做出自己的扩展——号称解决了代码重用问题;其二是 声明 某个子类 兼容 于某基类(或者说,接口上完全 兼容 于基类),外部调用者可无需关注其差别(内部机制会自动把请求派发[dispatch]到合适的逻辑)。
再说 多态 :基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。
很显然,多态实际上是 依附于继承的第二种含义 的。让它与封装、继承这两个概念并列,是 不符合逻辑 的。不假思索的就把它们当作可并列概念使用的人,显然是从一开始就被误导了。
实践中,继承的第一种含义(实现继承)意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。
继承的第二种含义非常重要。它又叫“接口继承”。
接口继承 实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做 归一化 。
归一化 使得外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,如果你需要,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。
归一化
1、面向对象原本要解决什么(或者说有什么优良特性)
似乎很简单,但实际又很不简单:面向对象三要素 封装、继承、多态
( 警告 :事实上,从业界如此总结出这面向对象三要素的一刹那开始,就已经开始犯错了!)。
封装 :封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,或者叫 接口 。
有了封装,就可以明确区分 内外 ,使得类实现者可以修改封装 内 的东西而不影响 外 部调用者;而外部调用者也可以知道自己不可以碰哪里。这就提供一个良好的合作基础——或者说,只要 接口 这个基础约定不变,则代码改变不足为虑。
继承+多态 :继承和多态必须一起说。一旦割裂,就说明理解上已经误入歧途了。
先说 继承 :继承同时具有两种含义:其一是继承基类的方法,并做出自己的扩展——号称解决了代码重用问题;其二是 声明 某个子类 兼容 于某基类(或者说,接口上完全 兼容 于基类),外部调用者可无需关注其差别(内部机制会自动把请求派发[dispatch]到合适的逻辑)。
再说 多态 :基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。
很显然,多态实际上是 依附于继承的第二种含义 的。让它与封装、继承这两个概念并列,是 不符合逻辑 的。不假思索的就把它们当作可并列概念使用的人,显然是从一开始就被误导了。
实践中,继承的第一种含义(实现继承)意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。
继承的第二种含义非常重要。它又叫“接口继承”。
接口继承 实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做 归一化 。
归一化 使得外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,如果你需要,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。
归一化