27 November 2013

首先要推荐一部最近看的非常赞的电影——《V字仇杀队》,其实多年前我就已经看过,近期又回顾了一遍,不仅台词剧情经典,其吐露出的思想也震人发聩。

不过瘾,那说说几本类似的书籍:大名鼎鼎的《1984》,赫胥黎的《美妙的新世界》《我们》,其实我都没读过,不过很有兴趣,找机会拜读一下。


今天开始研读大部头《Java编程思想》,开篇第一章讲的就是“面向对象编程思想”——“对象导论”。之前学过一点python,C++,哪个(教材)也没有上来就讲最难的部分(面向对象),可这本著作偏偏反其道而行,开篇就上主菜。

细细读来,开篇即为整部著作奠定了基调,似乎要从根本上扭转我们的思想,教会我们面向对象编程。通过大略的讲解,其为我们勾勒出Java语言的面向对象的编程思想精髓,让我们能从大局着眼。看来没有一定基础,这本书肯定难啃。另外,不得不说,这种安排却有其巧妙性。最重要的是,开篇这章讲的也确实精彩。

其实自己一直以来就抵触OOP,觉得这就是一些人发明的用来折腾人的东西,明明很简单的事情,偏偏要复杂化,弄出一堆像“继承”,“多态”这样“奇葩”的词汇。不久之前读到一篇文章——《为什么说面向对象编程和函数式编程都有问题》,其吐槽了一番面向对象编程和函数式编程(说实在的,我觉得函数式编程挺好的)。其实,有句话说的好:“只有两种编程语言:一种是天天挨骂的,一种是没人用的”,这也正验证了这句话。

其实OOP能走到今天,自然有其存在的必然性。就拿昨天那篇博客《python处理csv文件》来说,正是由于有这些库文件,我们才会如此方便的解决问题,很明显,这些库是面向对象式的,用起来很简单。没错,如果我们自己写程序自己用,怎么简单怎么来,但往往我们编写的程序要让别人用,OOP在这里就起到了很好的作用,它良好的封闭性、扩展性和接口等都给了使用者大大的便捷。当然,类似C语言也可以提供给我们写好的函数接口,但“类”的接口似乎更简单和人性化。另外,阅读代码时,OOP似乎更易读,尤其对于其他程序员来说。

OOP的思想是基于所要解决的问题来考虑,而不是基于计算机结构的考虑(C语言等)。没错,完全是两种思路,OOP是将问题空间中的元素及其在解空间中的表示称为“对象”,实质是:程序通过添加新类型的对象使其自身适用于某个特定的问题。书里说的也太“玄”了吧,举个例子,我们要解决用锤子砸钉子,问题空间中的元素就是“锤子”,“砸钉子”就是解空间中的表示。“锤子”是“类”,“砸钉子”就是方法了。作者所说的“把对象想像为‘服务提供者’”的方法其实很有效,真就是OOP的简化理解。

之前读过《高效程序员的45个习惯》,其中讲到:

继承和委托分别在什么时候使用:

如果新类可以替换已有的类,并且它们之间的关系可以通过is-a来描述,就用继承。

如果新类只是使用已有的类,并且两者之间的关系可以描述为has-a或是uses-a,就用委托。

那时候还不太理解委托是什么。其实委托即本书中提到的“组合”。组合即使用现有的类合成新的类(直接使用该类的一个对象,也可以将那个类的一个对象置于某个新的类中)。组合若是动态发生的,则被称为聚合。是has-a或uses-a的关系。

继承一个类型时,也就创造了一个新的类型,这个新的类型不仅包括现有类型的所有成员,而且它复制了基类的接口。单纯继承一个类相当于复制一个一模一样的类,没有什么实用价值,我们要让子类与父类有区别,这种区别有两种方法实现:

  • 直接在导出类(子类)中添加新方法:比如“鸟类”继承“动物类”,但是我们希望“鸟类”有自己的方法(比如翅膀颜色),就在子类中直接添加新方法。

  • 覆盖:即在子类重新定义继承来的方法,即实用相同的接口,但是接口实现的方法不同。

覆盖法使子类与父类的接口完全相同(只是具体实现不同),即为完全相同的类型,是is-a的关系。如果在子类中直接添加新方法,即是扩展新接口,基类(父类)不能使用,是is-like-a的关系。(这里需要注意,Java除了提供“组织”和“继承”外,还提供了“代理”,“代理”是介于两者之间的一种中庸的方法。2013.12.2加)

上面解决了之前遗留的问题,我们再来看看多态性。这里要说说“后期绑定”这个概念,对于非面向对象编程的编译器,其将产生对一个具体函数名字的调用,而运行时将这个调用解析到要被执行的的代码的绝对地址,即为“前期绑定”。而对于面向对象的编译器,被调用的代码直到运行时才确定。编译器确保被调用方法存在,并对调用参数和返回值执行类型检查,但是并不知道将被执行的确切代码,这便是“后期绑定”。Java使用一小段特使的代码来替代绝对地址调用。Java中,默认情况下是动态绑定的,不需要额外的关键字来实现多态。

看看书中这段很神奇的代码:

void doSomething(Shape shape) {
	shape.erase();
	//...
	shape.draw();
}

//某处用到了doSomething
Circle circle = new Circle();
Triangle triangle = new Triangle();
Line line = new Line();
doSomething(circle);
doSomething(triangle);
doSomething(line);

这里导出类被看做是它的基类的过程类,这个过程被称为“向上转型”,doSomething总是做了它该做的事情,调用Circle的draw(),调用Line的draw(),书中没细讲原理,仅仅说了是多态的原因,留在后面慢慢研究。

Java还提供了向下转型,第一章讲的不多,这里不多介绍,另外,Java完全采用了动态内存分配方式提供了被称为“垃圾回收器”的机制,它可以自动发现对象何时不再被使用,并继而销毁它Java还内置了异常处理,并强制你必须使用它Java的并发是内置于语言中的,并添加了大量额外的库支持

今天就先从大处着眼,简单的描述了面向对象编程思想,今后继续语法上的学习。



blog comments powered by Disqus