《程序世界》笔记2 面向对象2

动态语言和静态语言

静态语言

:像Java这样规定变量和算式类型的语言称为静态语言。不通过执行就可以发现类型不匹配这样的错误是静态语言的一个优点。为了实现多态性,静态语言被设计成这样,当给一个类变量赋值时,既可以用这个类的对象来赋值,也可以用这个类的子类对象来赋值。(也就是里氏替换原则)。这样可以实现多态性。

动态语言:动态语言对数据类型采取了另一种解决方法。类似于链表的实现方式,也就是对象本身记录有关自己种类的信息。这个思想的始祖是Lisp语言。(昨天我花了三个小时学习了这个语言,被深深的震撼到了。发张图大家来感受一下它的独特魅力。)

《程序世界》笔记2 面向对象2

lisp解释器的全部代码

动态语言允许调用没有继承关系的方法,也就是传说中的鸭子类型(DuckTyping)。程序有没有错误只有执行了才知道。那么什么叫鸭子类型呢。

DuckTyping(鸭子类型)

If it walks like a duck and quacks like a duck, it must be a duck.

(走起路来像鸭子,叫起来也像鸭子,那么它就是鸭子)。

鸭子类型的意义在于,即便一个类不是另一个类的子类,但是它只要拥有另一个子类的方法,做另一个子类方法类似的事情,那么他就可以被当作另一个类的子类进行多态调用。


继承的两种含义:

一种是“类都有哪些方法”,也就是说这个类都支持什么操作,即规格的继承。另一种是,“类中都用了什么数据结构和什么算法”,也就是实现的继承

静态语言中,这两者的区别很重要。在Java中,实现的继承用extends继承父类,规格的继承用implements来指定接口。但接口不能共享实现,这是个大问题,(注:就是所谓的虚方法,到时候还得自己在类中实现)

动态语言中,区分这两种继承意义不大。因为,动态语言采用鸭子类型。因此动态语言就没有继承规格这种概念,动态语言要解决的就是有层次的实现多重继承。

从多重继承变形而来的mix-in。这是ruby语言的特点,而python语言在编程时推荐使用这样的编程思想。ruby语言中通过include关键字在类中继承mix-in。而python在定义类的时候,classClassName(Parent,Mixin1,Mixin2)是一种多重继承,但编程时可以将第二个之后的父类定义为一种方法的集合,这就实际上相当于ruby语言的模块(module)了。

《程序世界》笔记2 面向对象2


两个误解:

第一个误解:对象是对现实世界中的具体物体的反应(错)

面向对象编程语言的共通功能:封装、数据抽象、多态。

结构化编程通过整理数据流,提高了程序的生产效率和可维护性。同样,面向对象编程通过对数据结构的整理,提高了程序的生产效率和可维护性。

如果把面向对象编程看做是对结构化编程的扩展,那么对象是否是现实世界中具体物体的反映就不重要了。实际上,面向对象编程语言中的对象,像字符串、数组和范围等,很多都没有现实世界中的具体物体与之对应。即使现实世界中有具体物体与之对应,对象也只是描述现实物体某一侧面的抽象概念而已。比如猫有颜色、血统等很多属性,而程序中的对象并不需要把这些属性都考虑进去。程序只是处理抽象数据的。

对象的模版=类

利用模块(已有代码)的手段=继承

因为继承只不过是抽象的功能利用方法,所以不必把对继承的理解束缚在“继承是对现实事物的分类的反映”。实际上这样的想法反而妨碍了我们对继承的理解。

第二个误解:多重继承是不好的(错)

对于像Java或者C++这样需要指定变量类型的静态语言来说,父类类型的变量可以用子类的对象来赋值。如果用子类以外的对象来赋值的话,就会发生编译错误。所以可以说这既实现了多态性,又实现了对变量类型的检查,是一个很好的想法。

但结果是,静态语言中可以实现多态性的只是限于拥有共通父类的对象。

所以,为了解决这个问题,多重继承在静态编程语言中是必要的。接口和类都是为了实现多重继承的技术,接口的出现是为了限制多重继承,防止复杂的继承结构。

动态语言同样需要多重继承。mix-in只是实现多重继承的一个技术。

总结:

为了使程序摆脱goto语句带来的混乱,我们发明了结构化编程。为了使程序能构更好的对数据结构进行整理,不重复使用代码,我们发明了对象和类这个概念。为了更好的利用更多已有代码,我们需要多重继承,为了限制多重继承的混乱,我们发明了接口,mix-in等技术。


分享到:


相關文章: