<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>冒号空间</title>
	<atom:link href="http://blog.zhenghui.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.zhenghui.org</link>
	<description>自然、人类、机器</description>
	<lastBuildDate>Fri, 16 Jul 2010 18:33:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>答读者问——对程序员的一些个人建议</title>
		<link>http://blog.zhenghui.org/2010/06/03/advice-on-programmer/</link>
		<comments>http://blog.zhenghui.org/2010/06/03/advice-on-programmer/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 04:35:30 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[计算机]]></category>
		<category><![CDATA[抽象]]></category>
		<category><![CDATA[数学]]></category>
		<category><![CDATA[程序员]]></category>
		<category><![CDATA[英语]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=716</guid>
		<description><![CDATA[答一位《冒号课堂》读者的提问]]></description>
			<content:encoded><![CDATA[
<h2><strong>答读者问</strong></h2>
<p>以下内容摘自<a href="http://bbs.zhenghui.org">冒号论坛</a>的一个<a href="http://bbs.zhenghui.org/topic/%E8%8F%9C%E9%B8%9F%E8%AF%BB%E3%80%8A%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%E3%80%8B%E5%90%8E%E7%9A%84%E6%84%9F%E8%A7%A6%EF%BC%8C%E6%9C%9B%E9%83%91%E6%99%96%E8%80%81%E5%B8%88%E8%A7%A3%E6%83%91">话题</a>，考虑其具有一定的典型性，故转至<a href="http://blog.zhenghui.org">冒号空间</a>，希望能对更多的读者有所帮助，也算是一种<span style="text-decoration: underline;">代码重用</span>吧。</p>
<p>&nbsp;</p>

<p><strong>读者Jee问</strong>：</p>
<blockquote>
<p>之前在Top  language里的一位网友像我推荐您的《冒号课堂》，书中eric向您建议开设社区，我猜测可能会有，就找到您的博客发现此地，很幸运您是一个如此有责任心的作者。</p>
<p>我是一名没有什么理论基础的不合格的计算机专业毕业生，毕业后却对软件方面技术非常感兴趣，可能与个性有关。于是在这近2年的找工作和工作过程中看了一些书，也和一些过来人聊过，总体来说让我对软件编程有了一点认识。在阅读您的冒号课堂之前，我曾一度认为我所差的是经验和一些诸如高级算法之类的进阶技术， 可现在，一个用了一个多月时间的夜晚阅读《冒号课堂》之后的我发现我所差的不仅仅是那些，而是最基础最根本的对计算机本身的认识，对数学的认识，对软件工程的认识。</p>
<p>我不想能有速成一说，只想能够现在正视自己，脚踏实地的一点一点的学习和进步，哪怕让我自学4年大学课程也未尝不可，只是有些时候有点找不到一个开始。我数学不好，作为一名程序员我想这是个令人沮丧的事实，我英语也不好，当看到蹩脚的一些翻译著作后痛苦不已。我想尝试着去改变这些，但是却不知该如何去做， 您知道，作为一名已经进入社会的成年人，我需要承受一些生存的压力和一些生活的负担，我希望能更好的利用每天那抽出来的时间，所以望郑晖老师能给我指出一条明道。</p>
<p>我一直没有说我从事的语言和方向，因为我知道这并不是核心，也不是想从您这得到如何学习XX语言等。万分打扰，还望见谅。</p></blockquote>
<p>&nbsp;</p>

<p><strong>作者</strong>hui答：</p>
<blockquote>
<p>你提到的问题十分典型，我非常理解你的心情，同时也非常乐意分享一些个人的看法。</p>
<p>虽然你在言语之中流露出不少负面的情绪，但我看到的却是正面的希望。首先，你对软件技术很感兴趣，而兴趣是学习和工作的最大动力。一般说来，我也没兴趣回答那些对编程不感兴趣者的有关编程的问题。一方面，我会劝他们改行，否则彼此都痛苦；另一方面，我建议的方法通常也不适合他们。其次，你很清楚地意识到自己在哪些方面不足，这是一切进步的基础。许多程序员意识不到自己的无知，甚至自以为足够有知，那又如何能进步呢？最后，你不指望任何捷径，愿意通过踏踏实实的学习来弥补不足。在浮躁之风盛行的当下，这点也是难能可贵的。</p>
<p>关于数学基础，窃以为并非什么太大的问题。几乎每个得知我数学背景的人都会对我说：哦，学数学的人来学计算机自然容易啦。事实上，这种观点虽然极为普遍，但也极为肤浅。本人从事数学14年（从本科算起）、从事计算机12年（与前者有部分重合），在这一点上还是比较有发言权的。事先说明，以下提到的数学不包括高中数学。其实大多数从事软件开发的人员用不到太多的数学知识，他们只需要正常的逻辑思维能力和抽象思维能力。整天拿数学说事，要么是无知，要么是找借口，要么是装高深。当然，我不否认一些高级算法、计算机理论以及人工智能等领域可能涉及到高深的数学知识（其实也只是图论、组合数学、数论、概率论、计算几何、抽象代数、数学逻辑等中的一小部分），但那毕竟只是少数。我也不否认自己的数学背景有助于对编程的理解，但投入产出比太低，不值得作为经验来推广。不过若想成为一位计算机科学家，那就另作别论了——这时数学懂得再多也会嫌少的。</p>
<p>倒是英语我希望你更重视些。我在<a href="http://blog.zhenghui.org/2009/09/10/colon- class-3_3/">《冒号课堂》中</a>专门提过阅读原著的必要性，而且你也意识到译著的质量问题。建议不必特地去学习英语（你本来就会了，不是吗？），只要坚持读经典原著即可。其实，计算机方面的英文算是很容易的了，关键是克服自己的惯性和惰性。开始可能不习惯，看多了就习惯了。在此提醒一点，在阅读时请有意识地培养自己对英语的语感，就像编程时要有意识地培养自己对编程语言的语感一样。</p>
<p>总之，<strong>对于程序员来说，数学没有人们认为的那么重要，英语没有人们认为的那么不重要</strong>。</p>
<p>再说说专业方面的问题。你提到愿意重新自学大学课程，虽精神可嘉，但未必可取。从软件（或建筑）设计的观点来看，这是<span style="text-decoration: underline;">bottom-up</span>法。作为学生，最好采用这种方法，但你已经参加工作了，所以我建议你更多地采用<span style="text-decoration: underline;">top-down</span>法。这当然不是轻视基础知识，而是认为获取知识最高效的方法莫过于<span style="text-decoration: underline;">按需</span>（on  demand）学习。在实际工作中意识到某个知识点的重要性，从而有针对性地弥补短板，这样学习起来不仅更有效率，也更有兴味。需要强调的是，绝不能只是 “头痛医头”，而要“拔萝卜带出泥”。只有寻根究底、以点带面，才能快速有效地建立起自己的知识结构体系。对于软件开发这类实践性很强的专业来说，该法尤其奏效。</p>
<p>话又说回来，这种项目驱动式的学习方法也是有一定局限的。毕竟大多项目涉及的深度和广度通常都很有限，单纯凭此建立起来的知识体系不可能非常完善。 这就需要平时有计划地阅读一些经典著作以加强深度，并定期浏览一些高质量的技术网站以加强广度。</p>
<p>以上谈的都是一些较为宏观的建议，我想你需要的是更加具体的建议。《冒号课堂》上已经阐述了不少关于编程语言、编程范式、设计原则方面的观点，此处不复赘言。我想特别强调一点——<strong>把握抽象</strong>（abstraction）。事实上，无论是在书中还是本论坛中，我都不厌其烦地再三提到抽象的重要性，今后有时间还会深入地挖掘这一主题。对编程的语言、范式、设计、实现体会得越深，对抽象体会得也越深。借用Hakell的设计者之一Paul  Hudak的一句略带夸张的话（overstatement）：<em>“abstraction, abstraction, abstraction” are  the three most important things in  programming</em>。一定会有人会问：难道编程语言就不重要了吗？设计模式就不重要了吗？算法设计就不重要了吗？那是他们尚未真正理解何为抽象——抽象不仅渗透在编程范式之中，也渗透在编程语言之中；不仅反映在设计原则之中，也反映在设计模式之中；不仅体现在架构设计之中，也体现在算法设计之中。</p>
<p>说来也怪，明明是想提“具体”建议的，偏偏又扯出了“抽象”，大概不是你想要的答案吧？既然你是计算机专业毕业的，又有一定的工作经验，其实也不需要太过具体的建议。你的苦恼是找不到努力的方向，而这个方向恐怕还是得靠自己去寻找。建议试试两种方法：研读一本有趣的名著或开发一个有趣的应用。只要深入其中，相信绝不会再为找不到方向而发愁，说不定倒会为方向太多而发愁呢。</p>
<p>最后，说句更实际点的话：如果平时能有意识地积累一些计算机以外的<span style="text-decoration: underline;">领域知识</span>（domain  knowledge），比如金融、电信、教育、企业管理等等，对提高个人在IT业的核心竞争力也是大有裨益的。当然，前提是你有兴趣或有条件获得这些知识。</p>
<p>一家之言，希望能对你有所帮助。</p></blockquote>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2010%2F06%2F03%2Fadvice-on-programmer%2F&amp;linkname=%E7%AD%94%E8%AF%BB%E8%80%85%E9%97%AE%E2%80%94%E2%80%94%E5%AF%B9%E7%A8%8B%E5%BA%8F%E5%91%98%E7%9A%84%E4%B8%80%E4%BA%9B%E4%B8%AA%E4%BA%BA%E5%BB%BA%E8%AE%AE">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2010/06/03/advice-on-programmer/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>分布&amp;分享——《分布式Java应用：基础与实践》推荐序</title>
		<link>http://blog.zhenghui.org/2010/05/27/preface-of-distributedjavaapp/</link>
		<comments>http://blog.zhenghui.org/2010/05/27/preface-of-distributedjavaapp/#comments</comments>
		<pubDate>Thu, 27 May 2010 11:51:27 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[计算机]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[书评]]></category>
		<category><![CDATA[分布式计算]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=701</guid>
		<description><![CDATA[《分布式Java应用：基础与实践》推荐序]]></description>
			<content:encoded><![CDATA[<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<h1 style="text-align: center;"><span style="font-family: 宋体;">分布&amp;分享</span></h1>
<!-- below comes from generated html -->
<div class="article" title="分布&amp;分享——《分布式Java应用：基础与实践》推荐序" lang="zh-CN">
<div class="titlepage">
<div>
<div>
<div class="author">
<h3 class="author">郑晖</h3>
</div>
</div>
</div>
<p>&nbsp;</p>
<hr /></div>
<div class="toc"><dl> <dt><span class="section"><a href="#content"></a></span></dt> </dl></div>
<div class="section">
<p>分布式计算不是一门年轻的技术,早在上个世纪70年代末便已是计算机科学的一个独立分支了; 它也不是一门冷僻的技术,从 C/S 模式到 P2P 模式,从集群计算到网格计算,乃至风靡当下的云计算, 都是其表演的舞台。另一方面,Java 作为一门应网络而生的语言,对分布式计算有着天然的友好性, 同时也是当今最流行的编程语言。然而令人稍感意外的是,以“分布式 Java 应用”为专题的书籍并不 多见,佳作则更少。至于国人所著者,请恕在下孤陋,尚未得见。不过细想之下,其实不足为奇。要 开发一个高质量的分布式 Java 应用,以达到高性能、可伸缩、高可用、低延迟的要求,同时保证一致性、容错性、可恢复性和安全性,是何等的不易啊。它对程序开发的挑战在于:不仅需要对 Java 语言、 类库、各种框架及相关工具极为熟悉,还需要对底层的 JVM 机制、各种网络协议有足够的了解;它对 分析设计的挑战在于:不仅需要熟悉传统的应用架构模式,还需要掌握适用于分布式应用的架构模式 和算法设计。此外,分布式应用对数据库管理员、测试分析人员等也提出了更高的要求。一本书若想涵盖这么多的内容,其难度可想而知。作者不仅需要具备起码的理论素养,更需要有丰富的实践经验。 如果仅仅是纸上谈兵,对读者是无甚裨益的。</p>
<p>正因如此,半年多前收到林昊先生的部分书稿时,便窃感欣喜,认定这是一个很好的选题。作为淘宝网的系统架构师,他有着令人艳羡的得天独厚的实践机会。尤其难得的是,林昊亲身经历了淘宝网的快速成长和转型期,饱尝其间的成败甘苦,从中也获得了许多宝贵的第一手经验。如今,他选择将这些经验以书籍的形式与众共享,对有志于分布式应用开发的读者而言无疑是一大福音。</p>
<p>本书的基础部分介绍了分布式 Java 应用的基本实现方式(重点是SOA)、相关的 JDK 类库和第三方框架,并对 JVM 的基本机制进行了深入解析;实践部分则关注于高性能、高可用和可伸缩系统的构建等。全书文风朴实,并附有大量的代码、数据和图表,比较符合大多数程序员的口味，也非常具有实践指导意义。如果用挑剔的眼光看,本书在深度、广度和高度上还有继续改进的余地,比如:对关键性的并发设计和算法设计可以介绍得更深入些;尚未涉及分布式应用中的安全问题;在性能调优一章中对 Java 源码级别的优化介绍似嫌不足; 未能高屋建瓴地总结和提炼出分布式应用独有的编程和设计原则、架构和思维模式,等等。当然,对于这样一本上乏经典可参、下需躬身实践的书籍来说,以上多属苛求。事实上,本人在审稿过程中也是获益良多。</p>
<p>另值一提的是,林昊先生利用业余时间写作,已是经年有余,其间数易其稿,且从善如流,充分体现了技术人员的求道精神。本书的主题在明是<strong>分布</strong>, 在暗则是<strong>分享</strong>——分享一段成长经历、分享一份宝贵经验,无论对作者还是读者,都是善莫大焉。</p>
<p dir="rtl">郑晖</p>
<p dir="rtl">2010年5月24日于广州</p>
</div>
</div>

P.S.

该书详情请见豆瓣：<a href="http://book.douban.com/subject/4848587/">分布式Java应用：基础与实践</a>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2010%2F05%2F27%2Fpreface-of-distributedjavaapp%2F&amp;linkname=%E5%88%86%E5%B8%83%26%23038%3B%E5%88%86%E4%BA%AB%E2%80%94%E2%80%94%E3%80%8A%E5%88%86%E5%B8%83%E5%BC%8FJava%E5%BA%94%E7%94%A8%EF%BC%9A%E5%9F%BA%E7%A1%80%E4%B8%8E%E5%AE%9E%E8%B7%B5%E3%80%8B%E6%8E%A8%E8%8D%90%E5%BA%8F">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2010/05/27/preface-of-distributedjavaapp/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>论思维的刚性与柔性（科学的迷信-中）</title>
		<link>http://blog.zhenghui.org/2010/04/22/hard-thinking-and-soft-thinking-2/</link>
		<comments>http://blog.zhenghui.org/2010/04/22/hard-thinking-and-soft-thinking-2/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 07:42:31 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[思维]]></category>
		<category><![CDATA[刚性思维]]></category>
		<category><![CDATA[哲学]]></category>
		<category><![CDATA[柔性思维]]></category>
		<category><![CDATA[科学]]></category>
		<category><![CDATA[科学哲学]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=694</guid>
		<description><![CDATA[<b>论思维的刚性与柔性</b>——科学的迷信（中）<br/>
•	一切科学都是假说<br/>
•	没有绝对理性的科学]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">论思维的刚性与柔性（科学的迷信-中）</span></h1>

<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/article.css" type="text/css"></head>
<!-- below comes from generated html -->   
<div lang="zh-CN" class="article" title="论思维的刚性与柔性"><div class="titlepage"><div><div><div class="author"><h3 class="author">郑晖</h3></div></div></div><hr /></div><div class="section" title="正文"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="content"></a>科学的迷信（中）</h2></div></div></div><p>
        </p><p>
            <span class="strong"><strong>三、一切科学都是假说</strong></span>
        </p><p>
            有两个司空见惯的词组：科学真理和科学假说。殊不知一个是自相矛盾，一个是同义反复。科学是人造的，真理是天造的，将二者并论，如同说“人造纯天然”一样滑稽。而“科学假说”的提法则与“人造非天然”具有相同的冗余度，因为所有的科学本质上都是假说。有人会说这是在抹煞科学假说与科学理论之间的区别，理由是前者是尚未证实的主观推测，而后者是被证实的客观真理。其实前面的讨论早已化解了这一责难，现在请出波普尔（Karl Popper）先生来一锤定音。
        </p><p>
            我们一直在谈论着科学，却从未明确地给出它的定义。与其重复乏味无趣、充满误导且毫无启示性的名词解释，不如探讨一个更有意义的问题：科学与非科学的划分标准是什么？对于这个<span class="term">划界问题</span>（demarcation problem），以逻辑实证主义为代表的证实主义坚持证实原则，即能被经验证实的理论便是科学，否则便不是。我们不再重述该观点的致命硬伤，只多言一句：证实论者看起来非常强调科学的客观性，自己偏偏违背了客观原则——对理论经过有限次检验后便断定其完全被证实，是不是太过主观了？波普尔的<span class="term">证伪主义</span>（falsificationism）反其道而行之，坚持证伪原则：一个理论是否是科学的，当且仅当它是<span class="term">可证伪的</span>（falsifiable）或<span class="term">可反驳的</span>（refutable）或<span class="term">可验证的</span>（testable）。乍听上去真有些荒诞，把科学与“真”（理）、（证）“实”这样的正面词汇相剥离已是有违常理了，现在竟然要与负面的（证）“伪”为伴了？居然还“当且仅当”？简直是“当当”两记闷棍嘛。
        </p><p>
            有必要先解释一下，所谓一个命题是可证伪的，并不是指它一定是错误的，而是指它在理论上容许有反例，或者等价地，它有可能被经验所否定。为更好地理解这个定义，不妨反过来思考：一个不可证伪的命题意味着什么呢？一种情形是命题在逻辑上永真，诸如2+3=5、“哥哥比弟弟年长”、“一周有七天”等等。另一种情形是命题无法被经验验证。比如“存在一个全知全能的上帝”、“我们生活的世界都是虚幻的”等等。逻辑学和数学中的命题属于第一种情形，因而这两门学科在波普尔看来都不属于科学。这并不奇怪，因为二者是纯粹理性的产物，并无经验上的意义。宗教和哲学中的命题属于第二种情形，所以宗教和哲学也属于非科学。请注意，这丝毫不意味着宗教命题或哲学命题是错误的或不重要的，仅仅是说它们无法被检验。
        </p><p>
            一个至关重要的问题是：可证伪理论的合理性在哪里？在回答这个问题之前，我们返回开篇的问题：科学为什么值得信赖？此前业已论证，科学并没有常人想象的那么可靠。科学研究的每个环节——观察、归纳、证实都不能保证它的绝对可靠性，更何况所有的科学理论还建立在假设之上。其实这些都还不是最关键的，它们只是科学工作者所关心的问题，普通民众并不关心也无从关心。可为什么后者对科学的信任度丝毫不亚于前者呢？当然不是因为他们直接参与或见证了科学研究的全过程，而是因为在日常生活中一再见识到科学的预见力（这种预见力一般通过技术来展现），从而感受到科学的价值和力量，以至于对科学坚信不疑。这也不难理解为什么古人更相信巫师、算命先生而不是科学家，因为当时的科学尚不具备令人信服的预见力。精准的预见力不仅给人们一种心理上的强烈震撼，还能带来更多新的事实。宇宙何其之大，事实何其之多，指望漫无目标的观察带来有价值的结果，无异于相信手执铁锹便可从自家后院里挖出金子。有了理论预测，人们才能针对性地安排一些实验，既可以有效地获得新发现，还能有效地检验新理论。可以想见，没有牛顿力学的预测，加勒（Johann Galle）不会从浩渺的天空中幸运地发现海王星；没有广义相对论的预测，爱丁顿也不会带领探险队远赴非洲观测日全食。
        </p><p>
            事情渐渐明朗了，判断一个命题是否有经验性的价值，关键看它是否包含目前尚未知晓的信息。“明天要么下雨要么不下雨”，对则对矣，可全无用处。“明天将要下雨”，虽未必对，但至少可作参考。有人会说：一个百分之百正确的命题岂不更有价值？此言差矣，如果一个命题不经经验事实的检验就能保证正确，那必要么是一个<span class="term">重言式命题</span>（tautology），要么是一个数学命题<a class="link" href="#note1"><sup>[1]</sup></a>，不能带来超出逻辑或数学以外的知识，故而算不得是一种经验预见。“好人死后上天堂，坏人死后下地狱”倒是包含了预见性信息，惜乎无法被证实，故而它的价值仅停留于宗教或道德层面而非经验层面。作为鲜明的对照，牛顿力学因准确地预见了海王星而达到辉煌的顶点，广义相对论因准确预言了恒星光线在太阳附近的偏转角而轰动世界。
        </p><p>
            波普尔的证伪（或称否证）学说深受“犹太三杰”——弗洛伊德、马克思和爱因斯坦的影响。他本人不仅也是犹太裔，而且可以算是弗洛伊德的徒孙（为弗洛伊德的弟子阿德勒工作过），早年（自认为）是一个共产主义者，与爱因斯坦也有过直接的交往。这三位以及其追随者对各自理论的态度大相径庭，令波普尔感触极深。精神分析学者从来不预测任何事情，但却宣称能解释一切事情。一个人因私利而杀人，他们可以解释；另一个人为正义而牺牲，他们也可以解释。马克思主义者也不遑多让，他们能把任何可以设想的事件解释为对他们理论的证实。资本家降低工资？那是对工人的剥削，是本性使然。资本家提高工资？那是为了调和劳资矛盾，乃情非得已。何时该坚持本国特色、何时该与国际接轨？只要“活学活用”辩证法，何愁不左右逢源？他们也不是全无预测，不过一旦预测失败，总能很轻易地通过引入辅助性的特设来挽救原有的理论。爱因斯坦的态度则迥然不同。他总是在寻求判决性实验，如果结果不出所料，并不能确证其理论；如果结果与预言相悖，则宣告理论失效。比如，他明确地声称：如果不能发现引力红移现象，那么广义相对论将是不可信的。强烈的对比让波普尔得出一个论断：<span class="strong"><strong>科学态度是批判的态度</strong></span>，必须彻底抛弃教条主义，让理论事先作出超出常识的、尽可能精确的预言，并坦然地接受实验的否证，而不是事后百般地辩解。由于因果关系的不对称性，预见结果比解释原因困难得多，因而先见之明比后见之明有说服力得多。这时候请股评家们来现身说法是再合适不过的了。提起前一天的股市行情，无论如何诡谲多变，他们都能分析得头头是道，“必然”二字贴满了一脸。可一到预测第二天的行情预测，他们便开始含糊其辞，扭头从“必然”王国走进了“自由”王国。
        </p><p>
            可证伪理论是时代的产物。牛顿的经典物理学曾被看作终极的宇宙真理，拉格朗日（Joseph Lagrange）的话道出了当时科学家的心声：“牛顿是伟大的，他发现了宇宙的规律；牛顿也是幸运的，因为宇宙只有一个。”随着相对论和量子力学的兴起，牛顿理论作为绝对真理的神话彻底破灭。作为这一科学史上重大事件的见证者，波普尔意识到：科学的本质不在于无误性，而在于可错性。此处的错，不一定指彻头彻尾的错误。例如，牛顿力学并未完全被否定，在宏观低速的领域仍然是适用的。爱因斯坦说得好：一个理论的最好命运莫过于它能指出一条通往一个更广泛理论的道路，而它在新的理论中作为一种极限情形继续存在。
        </p><p>
            证伪论的合理性还体现在它聪明地绕开了那些使证实论难以自拔的沼泽地。它不纠缠于认识论中有关知识的来源以及可靠性等问题，也不再枉费心机地为归纳法正名，更干脆地放弃了对科学的真理性的执着坚守，把传统的“观察－归纳－证实”的实证机制用“问题－猜想－反驳”的试错机制来代替。（或：问题1－尝试解决－消除错误－问题2）由于证伪过程是一种否定后件式的假言推理，属于<span class="term">演绎推理</span>（deductive reasoning），具有归纳推理所不具备的逻辑上的严格性。只是一个反例便足以推翻一个定律，这种类似“一票否决”的机制听起来未免过于残酷。对此波普尔的说法是：不可反驳性不是一个理论的长处，而是它的短处。不敢冒被反驳的危险的理论是没有实质性内容的，如果我们的目的是追求知识的增长，那么就应该放弃追求理论的（逻辑）高概率（没有任何实质内容的重言式概率最高）。理论的内容越丰富，则包含的信息越多，禁止发生的现象越多，也就越容易被未来的经验所反驳。从这里我们看到了经济学原理的影子：<span class="strong"><strong>理论的价值与风险成正比</strong></span>。此外，波普尔还把生物学中的进化论引入认识论，认为知识的增长是一个自然选择的结果，人类拥有的知识时时刻刻由迄今在适者生存的竞争中幸存下来的假说组成。
        </p><p>
            证伪论不仅重新定义了科学理论——可以被证伪但尚未被证伪的猜想或假说，也重新定义了科学态度——不是小心地呵护理论、谨慎地避免错误，而是不断地挑战理论、努力地发现错误并从错误中学习。必须了解，当一个理论完备到足以解释世间发生的任何事件的时候，当一个理论灵活到足以躲避任何攻击的时候，当一个理论被声称是放之四海而皆准、永远颠扑不破的时候，当一个理论被高喊着要坚决捍卫的时候，当一个理论被用作评判其他理论的标准的时候，恰恰是该理论远离真理接近教条、远离科学接近迷信的时候。
        </p><p>
            <span class="strong"><strong>四、没有绝对理性的科学</strong></span>
        </p><p>
            波普尔开创了<span class="term">批判理性主义</span>（critical rationalism）的先河，他的证伪论大胆新颖、简洁有力。但证伪论也有它的局限，同样要接受他人的批判，而这也正是它所倡导的。实际上，一个理论不可能因为一个反例就轻易地被否证。有时是因为反例本身来源于观察，而观察并不完全可靠；有时是因为忽略了某些不该忽略的因素；有时被否证的理论通过少量的修改可以继续存在。总之，否证论过于刚断激进，忽略了理论的柔韧性和稳定性（波普尔本人也意识到否证的界限并不总是那么清晰的）。例如，牛顿理论在解释水星<span class="term">近日点进动</span>（perihelion precession）的问题上遭到了困难，但人们并没有立即抛弃该理论，而是孜孜不倦地寻找支持的证据，甚至希望能有类似海王星那样的发现。直到广义相对论成功地解释这一现象并被广泛地接受后，这种努力才被放弃。此外，否证论是从微观的角度来探求科学发展的模式，全然忽略了科学理论的历史背景和整体框架。
        </p><p>
            库恩（Thomas Kuhn）是一个证伪论的反对者，当然也是证实论的反对者。他创造性地提出了一套<span class="term">范式</span>（paradigm）理论，认为科学的发展不是线性递增的渐进过程，而是周期性的革命或突变，即<span class="term">范式转移</span>（paradigm shift）（这一术语并非库恩创造的，不过后来被广泛地应用于其他领域）。所谓范式，不是指某个具体的理论，而是指<span class="term">科学共同体</span>（scientific community）共有的世界观和方法论，包括价值标准、形而上学原则、符号体系、理论框架、应用方法等等。通俗地说，范式就是看待问题和解决问题的模式与套路，既有客观成分——理论和方法体系，也有主观成分——心理信念。据此，库恩把科学的发展过程描述为如下几个周期性的阶段——
        </p><div class="blockquote"><blockquote class="blockquote"><p>前科学－常态科学－危机－革命－新的常态－新的危机</p></blockquote></div><p>
            在从事某一学科的研究者对共同研究的问题尚未达成基本共识之前，该学科处于<span class="term">前科学</span>（prescience）阶段。各种候选范式激烈碰撞、互相融合，最后脱颖而出的范式成为公认的准则。于是，研究活动开始从无组织到有组织、从多样化到单一化，此时便进入<span class="term">常态科学</span>（normal science）阶段。拥有统一范式的学科标志着它的成熟，库恩以此作为区别科学与非科学的一个重要特征（虽然他并不十分热心划界问题）。在常态科学阶段，科学家们倾向于维护和发展现有的框架，不会轻易地否定它。即使出现一些难以解释的<span class="term">反常</span>（anomaly）现象，也会尽量地通过修正理论来克服。在经过一段稳定期之后，困难愈来愈多、愈来愈严重以至失去控制，科学家们的固有信念渐渐动摇，<span class="term">危机</span>（crisis）随之来临。直到一种能有效化解危机的新型范式出现，并被越来越多的科学家认同的时候，<span class="term">科学革命</span>（scientific revolution）便产生了。
        </p><p>
            举一个范式转移的实例。19世纪末，经典物理学取得了无与伦比的全面成功，作为三大支柱的经典力学、经典电磁学和经典热力学，当仁不让地成为各领域的范式。物理学家们无不踌躇满志，俨然已掌握了大自然的终极密钥，早把哲学家们的谆谆告诫抛诸脑后。孰料天空飘来的“两朵乌云”（迈克尔逊-莫雷实验与黑体辐射实验）引起了一场暴风骤雨，看似坚不可摧的物理学大厦竟变得摇摇欲坠。幸得相对论与量子力学应运而生，分别驱散了这两朵乌云，最终让物理学安然度过危机。它们也众望所归地成为两个崭新的范式，完成了现代物理学的一次重大革命。
        </p><p>
            范式理论不仅否定了科学的渐进性，更对科学的客观性提出了挑战。即使当前范式百孔千疮，科学家们仍倾向于坚守，这已不能用事实或理论来解释，只能说与信念有关。量子力学奠基人普朗克（Max Planck）迫于情势提出了量子假设，但出于对经典范式的深深信念，后期一直试图把自己的假设纳入其中。他曾深有体会地说：“一个新的科学真理并不是靠说服它的对手并使其看见真理之光取胜，而是由于它的对手死了，新的一代熟悉它的人成长起来了”即使比普朗克显得更为开放的洛伦兹（Hendrik Lorentz），也遗憾没有在旧的基础崩溃之前死去。范式信念的烙印之深，由此可见一斑。难怪库恩把范式转移比作心理学上的<span class="term">格式塔</span>（Gestalt）转换、宗教上的改宗、政治上的改革。无知的现代人常常会忍不住嘲笑亚里士多德的理论，诸如五大元素说、地心说、重力说等，是否想过自己又会怎样地被后代嘲笑呢？不同的历史时期有不同的范式，那是近乎宗教般的信仰，岂是轻易可以超越的？
        </p><p>
            同样地，一个新范式的接受与否也不全靠严密的逻辑论证或严格的实践检验，有时取决于科学直觉、宗教或哲学观点、对和谐的信念、个人心理、社会心理等非理性因素。比如哥白尼反对地心说的一个根据是：它的体系过于复杂，不能彰显造物主的伟大。他提出的日心说在当时并没有足够实验数据的支持，相反还有不少不利的事实，但由于比地心说更简洁、更自然，仍吸引了不少包括开普勒和伽利略在内的科学家参与到新范式的建构中来。“让一个方程符合美比符合实验更重要”狄拉克（Paul Dirac）这句“唯心”的名言在麦克斯韦方程组中得到了最好的应验。麦氏方程组从内容到形式无不体现出科学的和谐与美妙，人们在惊叹的同时也加深了对其正确性的信念。只可惜，美并没有一个量化的标准。开普勒的行星轨道方程在很长时间内不被接受，就是因为包括伽利略在内的科学家都不喜欢椭圆，认为正圆才是最高贵最完美的。无论宗教、哲学、美学等带给人的启示是正面的还是负面的，它们都实实在在地影响到了范式的接受程度。此外，社会因素也不可忽视。爱因斯坦的相对论在很长时间里只有极少数人能真正理解，可为什么很快能广泛地被世人所接受？除了有限的实验支持和理论本身的优美之外，媒体和科学界推动的<span class="term">社会建构</span>（social construction）也是功不可没的<a class="link" href="#note2"><sup>[2]</sup></a>。
        </p><p>
            库恩认为范式具有<span class="term">不可通约性</span>（incommensurability），即不同的范式之间难以比较，没有绝对的好坏标准。但他本人拒绝被冠以<span class="term">相对主义</span>（relativism）的帽子，理由是他并不否认范式革命的进步性和不可逆性。不过下面的例子多少说明相对主义也不无道理。亚里士多德认为行星的圆周运动是自然的、无需解释的。牛顿认为匀速直线运动才是自然的，行星作（近似）圆周运动是由于引力作用。他同样也没有解释其中的原因，只是把它们分别归结为自己的第一运动定律和万有引力定律。在后人看起来，牛顿的说法无疑是更科学的。然而到了爱因斯坦那里，万有引力再次消失，行星轨道的弯曲是因为时空弯曲的缘故。如果认同广义相对论，那么亚里士多德的说法岂不是在某种程度上比牛顿的更接近真理？<a class="link" href="#note3"><sup>[3]</sup></a>
        </p><p>
            比较几种不同的科学观，大致可以说：逻辑实证主义重在真，波普尔重在善，库恩重在美。逻辑实证主义强调科学的真理性，那是毋庸置疑的。何以说波普尔重在善呢？波普尔批驳了逻辑实证主义一厢情愿的求真信念，提倡理性的批判精神，由此而带来的美德将是：诚实公正、尊重他人、勇于认错、反对权威、鼓励开放、崇尚自由、提倡民主，等等。波普尔的这种求善思想在《开放社会及其敌人》中得到最明显的体现，尽管那不是一本科学哲学方面的著作。库恩则强调科学的发展不是单靠自身内部的逻辑力量，还深受社会文化的影响。他认为不同的范式之间在逻辑上并无优劣之分，选择的标准不完全是客观的，还有包括审美（简单、对称、和谐、一致、优雅等）、直觉、信念、价值判断等在内的心理要素。
        </p><p>
            拉卡托斯（Imre Lakatos）认为波普尔的证伪论过于朴素（如忽略了理论的坚韧性和整体性），库恩的范式论过于非理性（如过分强调社会和心理因素），集二者之大成提出了科学研究纲领方法论。<span class="term">研究纲领</span>（research programme）是一组具有严密内在结构的科学理论系统，由中心的<span class="term">硬核</span>（hard core）和周围的保护带（protective belt）组成。其中硬核是纲领的不容反驳的基础理论，保护带是容许反驳的辅助假设。比如，地心说是托勒密天文学研究纲领的硬核，牛顿三大运动定律和万有引力定律是牛顿力学研究纲领的硬核。当研究纲领遭遇反常现象，将通过修改保护带来维护硬核，使研究纲领免遭证伪。一方面，拉卡托斯继承了库恩的<span class="term">历史论</span>（historicism）和<span class="term">整体论</span>（holism），把范式改造为研究纲领，承认科学家们协同地在一个框架内工作，但否定框架之间的不可通约性以及框架选择对信念的过分依赖性。另一方面，他把波普尔的<span class="term">朴素证伪论</span>（naïve falsificationism）在划界标准和证伪规则上进行了改造：一个理论被称为是科学的，仅当它比其先行或与其竞争的理论有更强的发现新颖事实的能力之时<a class="link" href="#note4"><sup>[4]</sup></a>；一个理论被证伪，当且仅当另一个理论有更强的解释和预测能力。拉卡托斯的<span class="term">精致证伪论</span>（sophisticated falsificationism）否定了判决性实验的存在，保证了科学理论发展的连续性。
        </p><p>
            正统的科学观受到越来越强烈的质疑，波普尔无情地把科学置于证伪的烈火之上炙烤，库恩悄悄地在科学的土壤里播下革命的种子，拉卡托斯小心地给科学裹上保护带浸泡在反常的海洋之中。但在费耶阿本德（Paul Feyerabend）的眼里，这三位还是显得过于委婉和温情了。他抡起<span class="term">认识论无政府主义</span>（epistemological anarchism）的大锤，二话不说就砸碎了科学的圣像。听听他的发言——
        </p><div class="blockquote"><blockquote class="blockquote"><p>科学只是人类众多思想形态的一种，但并不一定是最好的一种。</p><p>科学的优越性不是被论证的，而是被假定的。</p><p>科学是最新、最富有侵略性、最教条的宗教机构。</p><p>认识论无政府主义者会毫不反悔地为最陈腐或最荒诞的陈述辩护。</p><p>不存在着什么“科学的方法”。</p><p>如果存在着一种永远不变的科学方法原则，那就是“怎么都行”（anything goes）。</p><p>科学是一种本质上属于无政府主义的事业。</p><p>专家的意见经常带有偏见，是不可靠的，需要有外部控制。</p><p>外行可以而且必须监督科学。</p><p>
                如果科学由于它的成就而受到称赞，那么神话应该受到百倍的称赞。因为神话的发明者开创了文化，而科学家只是改变了文化，而且并非总是改得更好。
            </p></blockquote></div><p>
            持传统科学观点者听到这些难免会耳热心惊，甚而会因心中的女神被亵渎而恼羞成怒。然平心而论，费氏观点虽有偏颇之处，却也不无道理。他正确地意识到：理论的增长是对科学有益的，而齐一性则损害科学的批判力和创造力；不顾具体条件而硬性规定一些所谓科学的规则，不仅不会给科学带来什么帮助，反而会阻碍科学的发展。他还通过自己对中医的切身经历，得出一个结论：仅仅因为中医不符合西医的理论或规则而将其排斥是十分荒谬的<a class="link" href="#note5"><sup>[5]</sup></a>。费耶阿本德对缺乏人性关怀的<span class="term">科学主义</span>（scientism）也深恶痛绝，认为科学最重要的问题不是求真，而是求善，即它在何种程度上增加了个人的幸福和自由。他一方面批判科学方法论、理性主义和科学沙文主义，一方面提倡科学的民主化、研究方法的多元化和非理性的合理化，从而填平了科学与非科学之间的鸿沟，消解了理性与人性之间的矛盾。正如休谟那样，费耶阿本德的目的是：<span class="strong"><strong>用理性反思理性，将人性注入理性</strong></span>。人们往往对“无政府主义”这样的词汇有天然的反感，但认识论的无政府主义完全不同于政治上的无政府主义。尤其是，费耶阿本德声称它只是在为时代把脉后开的一剂猛药（偷师中医？）。既然是药，就难免有毒，也不可能永远吃下去，否则必会矫枉过正。或许下面这句话更能反映他的本意——
        </p><div class="blockquote"><blockquote class="blockquote"><p>今日之科学或是明日之童话，今日之神话或是明日之科学。</p></blockquote></div></div><div class="section" title="注释"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>注释</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    维特根斯坦（Ludwig Wittgenstein）认为数学也是重言式。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    相对论在最初的接受中部分地得益于倡导者的威信与资源，但最终还是靠实践检验。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    程序员还可以考虑<span class="term">编程范式</span>（programming paradigm）的例子。过程式、对象式（OOP）、函数式、逻辑式等不同的范式各有优劣，没有绝对的高下之分。
                </p></li><li class="listitem"><p><a name="note4"></a>
                    这意味着：新理论在逻辑上包含更多的经验内容，并且其中有些已被证实。
                </p></li><li class="listitem"><p><a name="note5"></a>
                    这里的关键不在于争论中医是不是一门科学，而在于它有没有实用价值和研究价值。
                </p></li></ol></div></div></div>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2010%2F04%2F22%2Fhard-thinking-and-soft-thinking-2%2F&amp;linkname=%E8%AE%BA%E6%80%9D%E7%BB%B4%E7%9A%84%E5%88%9A%E6%80%A7%E4%B8%8E%E6%9F%94%E6%80%A7%EF%BC%88%E7%A7%91%E5%AD%A6%E7%9A%84%E8%BF%B7%E4%BF%A1-%E4%B8%AD%EF%BC%89">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2010/04/22/hard-thinking-and-soft-thinking-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>论思维的刚性与柔性（科学的迷信-上）</title>
		<link>http://blog.zhenghui.org/2010/04/19/hard-thinking-and-soft-thinking-1/</link>
		<comments>http://blog.zhenghui.org/2010/04/19/hard-thinking-and-soft-thinking-1/#comments</comments>
		<pubDate>Mon, 19 Apr 2010 08:08:59 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[思维]]></category>
		<category><![CDATA[刚性思维]]></category>
		<category><![CDATA[哲学]]></category>
		<category><![CDATA[柔性思维]]></category>
		<category><![CDATA[科学]]></category>
		<category><![CDATA[科学哲学]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=682</guid>
		<description><![CDATA[<b>论思维的刚性与柔性</b>——科学的迷信（上）<br/>
•	没有绝对可靠的科学<br/>
•	一切科学都建立在假设之上]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">论思维的刚性与柔性（科学的迷信-上）</span></h1>

<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/article.css" type="text/css"></head>
<!-- below comes from generated html -->   
<div lang="zh-CN" class="article" title="论思维的刚性与柔性"><div class="titlepage"><div><div><div class="author"><h3 class="author">郑晖</h3></div></div></div><hr /></div><div class="section" title="正文"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="content"></a>科学的迷信（上）</h2></div></div></div><p>
        </p><p>
            科学，一个神圣的词汇，作为名词是真理的同义语，作为形容词是正确的换喻词。渺小的人类正是依仗科学这把神兵利器，俨然已可与大自然分庭抗礼。从来没有一种信仰能象科学那样深入人心，胆敢怀疑科学者似乎不是愚昧便是狂妄。本节标题把科学与迷信并列，绝非哗众取宠，而旨在说明一个现象：科学在破除大量迷信的同时，也渐渐变成了一种新的迷信。
        </p><p>
            有关科学的神话不胜枚举，下面是一些最常见的说法——
        </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">科学是客观纯粹的、绝对理性的、价值中立的、普遍正确的、确定无疑的</li><li class="listitem">科学观察是客观的、价值无涉的，并且先于科学理论</li><li class="listitem">科学的发现均始于观察，完全依靠逻辑推理，因此结论是可靠的</li><li class="listitem">科学建立于事实之上，科学实验是客观的、可重复的，因而科学是可靠的</li><li class="listitem">科学真理是可以被证明的，科学理论就是被证实的科学假说</li><li class="listitem">科学不需要假设</li><li class="listitem">科学是精确的，至少可以无限地趋于精确</li><li class="listitem">科学的发展完全是由其自身的内部逻辑力量推动的</li><li class="listitem">	科学终究能了解宇宙的终极真理，是万能的（在广度和深度上没有极限）</li><li class="listitem">科学没有边界，也没有极限</li><li class="listitem">不符合科学、不能用科学来解释的东西都是无用的或不正确的，应当坚决摒弃</li><li class="listitem">科学不需要形而上学</li><li class="listitem">科学与宗教不相容</li><li class="listitem">科学给人类带来幸福</li></ul></div><p>
            接下来我们将一一刺破这些迷信的肥皂泡。为了让话题更加集中，如无特别说明，以下科学主要指狭义的自然科学。
        </p><p>
            <span class="strong"><strong>一、没有绝对可靠的科学</strong></span>
        </p><p>
            首当其冲的一个问题是：科学如此值得信赖的根本原因是什么？也许可以换种问法：科学与其他途径获得的知识有何本质的不同呢？最常见的一种解释是：科学是从客观事实中严格推导出来并通过实践检验的。言下之意，从可靠的事实出发作可靠的推理，得出的结论自然也是可靠的，更何况还要经过反复的验证。真是环环相扣、无懈可击，简直不容置疑。事实上，我们的思维早已被训练得如此地刚性，以至于对此哪怕只闪现一丝怀疑的火花，都会本能地自行掐灭，以防灼伤大脑。本着寻根究底的科学精神，我们发现以上解释实际上隐含着三个观点：一、人的感官经验（sense experience）是确实的和精确的——<span class="term">实证主义</span>（positivism）的观点；二、从一系列特殊的事实能推出一般性的结论——<span class="term">归纳主义</span>（inductivism）的观点；三、被经验证实（empirically verified）的理论是有效的——<span class="term">证实主义</span>（verificationism）的观点。随着哲学标签的引入，我们的讨论开始弥漫起学术的气息，希望您感到的是陶醉，而不是晕眩。下面，让我们试着往思维中掺入一点柔性的元素，以审视的目光重新打量这三个观点。
        </p><p>
            <span class="strong"><strong>1. 关于经验观察的可靠性：</strong></span>
            人们永远不可能通过观察获得绝对客观的事实。
        </p><p>
            首先，由于测量仪器精度有限、测量方法或理论公式不够完善、实验条件不尽理想、实验者存在生理局限，实验中的各种偶然误差和系统误差无法避免。随着实验手段的进步，测量误差可以降低，但永远不可能完全消除。海森堡的<span class="term">不确定性原理</span>（uncertainty principle）甚至从理论上保证了有些成对的物理量（如位置与动量）不能同时达到任意精度。有人认为只要测量误差足够小，那么对结果的影响总是可以忽略不计的。可惜<span class="term">混沌</span>（chaos）现象的出现破坏了这种乐观的情绪，人们发现一个非线性动力系统可能会对初始值具有极其敏感的依赖性，即俗称的“蝴蝶效应”。换言之，一个混沌系统对测量误差是零容忍的。
        </p><p>
            其次，观察者的测量行为可能影响到被观察的事实。正如量子力学中所揭示的那样，观察者既是观众，又是演员。当我们测量水温时，温度计已经改变了水温；当我们测量轮胎气压时，已经放跑了部分气体。
        </p><p>
            最后，观察者的客观性存疑。种种实验表明，人的感官并不绝对可靠。耳听固然是虚，眼见也未必为实，难道忘了我们是怎么一次次地被魔术师们欺骗的吗？不仅如此，观察者的实验行为依赖于其理论知识和实验目的，同时也掺杂着个人情感和价值判断，从而不可能做到绝对的中立、客观和理性。一个家喻户晓（但未必真实）的例子是牛顿因观察到苹果的落地而得出了万有引力定律，为什么其他人都熟视无睹？另一个著名案例来自密立根（Robert Andrews Millikan），他在作油滴实验时有意识地去掉了“丑陋的”数据以迎合完美的理论，并因此获得了诺贝尔物理学奖。
        </p><p>
            <span class="strong"><strong>2. 关于归纳推理的可靠性：</strong></span>
            归纳推理（数学归纳法除外）是不严格的。
        </p><p>
            实验事实通常具有特殊性，在逻辑上表现为一个<span class="term">特称命题</span>（particular proposition）。科学理论通常具有一般性，在逻辑上表现为一个<span class="term">全称命题</span>（universal proposition）。从一组特称命题推导出一个全称命题，被称为<span class="term">归纳推理</span>（inductive reasoning）。容易看出，这种推理并无逻辑上的保障。即使发现一万只乌鸦全是黑的，也不能断定“天下乌鸦一般黑”。对此，归纳主义者提出：应观察大量的事实，如果这些事实均符合同样的规律，则可断定理论成立。可究竟多大才算“大量”？没有一个公认的标准。不仅理论的必然性无法保证，甚至连大概率的正确性也是一种奢望。因为事实总是有限的，而理论涵盖的对象却通常是趋于无限的，有限的样本相对无限的取值空间而言，在概率上都趋于零。更何况有些实验是无法多次进行的，举个极端的例子：原子弹的杀伤力实验在整个世界历史上只进行过两次。
        </p><p>
            归纳法除了有数量问题外，还有个时间问题：过去成立的事实不代表将来也会成立。极端如休谟（David Hume）者，甚至拒绝相信明天的太阳定会升起，哪怕它此前从未旷过一天工。如果您闻听此言有将其暴打的冲动，不要忘记他可是近代最重要哲学家之一（许多人认为“之一”二字都是多余的），既不痴傻疯癫，也非胡搅蛮缠。有人据理力争：归纳法不是在以前的理论形成中屡试不爽吗？哼哼，休谟又在一旁冷笑了：这分明是在循环论证！归纳法在场合A是成功的，归纳法在场合B是成功的，。。。，由此推出归纳法在任何场合都是成功的。这个推理本身不正是归纳推理吗？用归纳推理来论证归纳推理的正确性，不是循环论证是什么？每当NBA评论员用历史数据来预测胜负的时候，每当某些人动辄以“历史证明”来寻求其断言的合理性的时候，不知道他们的颈后是否感受到来自休谟鼻孔里的森森凉气？
        </p><p>
            对于归纳法的另一个质疑容易受到忽视，但同样令归纳主义者感到如芒在背。众所周知，实验数据通常是有误差的，而理论公式通常却是精确的。回忆一下，胡克定律、欧姆定律的线性正比关系，库仑定律、万有引力定律的平方反比关系，哪一个不是简洁精确的？试问：从不够精确的特殊事实如何能推导出精确的一般结论？从严格意义上说，恐怕连归纳推理都算不上吧？
        </p><p>
            <span class="strong"><strong>3. 关于理论检验的可靠性：</strong></span>
            一个理论无论被成功地检验过多少次，也不能被证实。
        </p><p>
            该问题从某种意义上说是上两个问题的重复，只不过一个发生在理论确立之前，一个发生在理论确立之后。实验结果与理论预测常会有一定的出入，而误差的允许范围并无明确的界定。更糟的是，人们在检验理论之时往往比建立理论之前带有更多的主观性。为了维护现有的理论，支持者总会精心挑选有利的事实或者增加辅助性的特设来自圆其说，颇有“事后诸葛亮”的嫌疑——心理学上称之为<span class="term">后视偏差</span>（hindsight bias）。倘若一个理论在验证过程中陷于为辩护而辩护、为修正而修正的境地，那么很可能已经偏离了真理的航道。地心说便是一个典型实例。该学说在解释行星运动时一再遇到困难，但支持者们总能找出一些牵强的理由和生硬的假设来挽救。例如，为了解释行星逆行现象，托勒密（Claudius Ptolemaeus）专门提出本轮（epicycle，周转圆）理论。地心说就这么一路缝缝补补，竟然也流行了两千年，直到为哥白尼的日心说所取代。
        </p><p>
            科学的可重复性原则也是为人津津乐道的。相当一部分人认为，当一个理论在被不同的人、不同的时间、不同的地点被反复验证后，其正确性便可以得到保障。特异功能被斥为伪科学的一个原因便是其不具备可重复性。事实上，验证次数不是一个绝对的衡量标准。1919年，爱丁顿（Arthur Eddington）的一次日全食观测便成了<span class="term">判决性实验</span>（crucial experiment），此前无数次被检验的经典力学在一夜之间变得脆弱不堪，而头一回被检验的广义相对论则开始逐渐为人们所接受。再者，可重复性本身就是一个相对的概念，任何两次实验都不可能完全地对等。有些理论囿于客观条件、伦理道德等限制，直接检验的机会极少，甚至完全没有，主要通过理想实验、模拟实验、替代实验等间接方式。如进化论、宇宙大爆炸理论、一些生物医学理论，等等。
        </p><p>
            <span class="strong"><strong>二、一切科学都建立在假设之上</strong></span>
        </p><p>
            传统的<span class="term">认识论</span>（epistemology）认为，（科学）知识是观念符合对象的结果。至于二者是如何相符的，在近代西方有两种截然不同的观点：一个是笛卡尔（Rence Descartes）创立的<span class="term">唯理论</span>（rationalism），主张知识源于先天观念，推崇演绎法；另一个是培根（Francis Bacon）创立的<span class="term">经验论</span>（empiricism），主张知识源于感官经验，推崇归纳法。两大派别多年来一直争战不息，休谟的出现更加剧了二者的矛盾。他从经验论的阵营中杀出，把经验论引向<span class="term">怀疑论</span>（skepticism）的死胡同，并通过否定归纳原理断绝了它的归路。不等唯理论幸灾乐祸，休谟回手对它的软肋发出致命的一击——否定绝对的因果律。每当人们说“太阳把石头晒热”的时候，休谟就会不识时务地跳将出来：凭什么说“太阳晒”导致了“石头热”？我能够感受到的只是太阳晒和石头热，却感受不到二者的因果关系。人们之所以相信两种现象之间因果联结，只是因为它们恒常地前后相伴。但那不过是一种下意识的联想或习惯性的信念，找不到任何逻辑的依据。很显然，一旦因果链条被割断，唯理论的战车将彻底陷入瘫痪。休谟的破坏力还不止于此，他坚称：观念就是观念，永远不可能是对象，谁也不能保证它们一定相符，从而把整个认识论推向彻底的<span class="term">不可知论</span>（agnosticism）。如果您觉得休谟在无理取闹，那就大错特错了。他的观点尽管令人不快，却是无可辩驳的。当人们确信自己的主观认识符合了客观事实的时候，却未意识到这本身就是一个主观判断，与先前的归纳推理一样坠进循环论证的泥沼。从实质上看，唯理论以非理性的方式来坚持理性，而休谟以怀疑理性的方式来坚持更纯粹的理性。作为一个“温和的怀疑论者”（休谟自称），休谟一方面拒绝轻信和盲从，一方面为冷冰冰的科学注入人性，明确划分了知识与信仰的界限，并为理性和宗教的盲目崇拜者分别开了一副清醒剂。
        </p><p>
            休谟撬动了人们一直迷信的科学理性的根基，也将另一位哲学伟人——康德（Immanuel Kant）从<span class="term">独断论</span>（dogmatism，或译为教条主义，此处指唯理论）的沉梦中惊醒。后者从此开始了长达十一年的闭关修炼，终于推出划时代巨著《纯粹理性批判》（Critique of Pure Reason），力图在独断与怀疑、理性与经验、演绎与归纳、唯物与唯心之间取得调和。鉴于唯理论无法解释科学知识的经验依赖性，而经验论又无法解释科学知识的普遍必然性，康德创立了<span class="term">先验唯心论</span>（transcendental idealism）。他的一个论点是：科学知识源于<span class="term">先天综合判断</span>（synthetic a priori judgment）。打个粗糙的比方，如果把人脑比作电脑——当然是能自动开发和升级软件的超级电脑，当这台电脑刚出厂时，唯理论者认为它已是各种软件齐备，经验论者它认为只是一台裸机，而康德折衷地认为它仅预装了操作系统的<span class="term">内核</span>（kernel）。他有一句惊世骇俗的名言：“我们的理智不是从自然引出规律，而是把规律强加于自然”，并且毫不谦虚地把自己的这套理论比作哥白尼式的革命（反对者则讽刺为托勒密式的反革命）。其理由是：哥白尼把“太阳围绕地球转”改成了“地球围绕太阳转”，而他把“（认识的）主体围绕着客体转”改成了“（认识的）客体围绕着主体转”。即知识不是观念符合对象，而是对象符合观念。在他看来，经过这样的关系反转，认识论的难题便会迎刃而解。
        </p><p>
            康德哲学并非无可挑剔，但有一点是不易之论，即所有的科学理论都是人给自然设立的法则，哪怕后者未必遵从。对此一个有力的支持证据是，所有的科学理论均建立于人为的假设之上。不少人会觉得不可思议，因为在他们的潜意识里，科学与假设是互相对立的概念——科学理论都是真理啊，“真”理岂能“假”设？不妨这么说，如果一套科学理论是一座大厦，那么事实是砖石，而假设是地基。没有事实，科学理论固然无法构建；但没有假设，科学研究甚至无法开始。
        </p><p>
            有一个假设是所有的科学都无法逃避的，即科学研究的对象是有规律的。（如果您觉得这本是天经地义的话，请复习以上休谟先生的发言）人们采纳该假设绝不是因为证明了客观规律的存在性，而是出于一种信念，或者一种无奈——倘若不信，我们还能做什么呢？柏格森（Henri Bergson）就认为，所谓的规律只是科学家脑中歪曲的图像。
        </p><p>
            关于规律的假设还得进一步加强：规律不仅存在，而且要足够地简单，简单到可以为人类所认识。（如果您觉得这是在侮辱人类的智慧，那一定是对人类的智力水平作了未经证实的假设）为什么那么多的物理定律可以用简单而精确的数学公式来表达？正如前文指出的那样，这些定律从未被真正证明过，不只是因为归纳法的局限，也因为粗略的实验数据无法严格地验证精确的数学关系。这些定律能被广泛接纳，仅仅是因为科学家们坚信规律应当是简单的。假如一定要拒绝规律的简单性假设，那么就得承认科学理论不是真理，至多只是对规律的简化描述。
        </p><p>
            仅仅假设客观世界是有规律的、可认知的还远远不够，科学家们在研究过程中总会有意无意地增加许多实用的假设。比如，声称“我不作假设”的牛顿在他的力学理论无意中用到了绝对时间的假设，而爱因斯坦在他的狭义相对论中则有意地引入了光速不变的假设。为了更好地说明问题，我们介绍一下大科学家庞加莱（Henri Poincaré，也译为彭家勒）提出的<span class="term">约定论</span>（conventionalism）。该理论认为，在科学创造过程中总会选择一些<span class="term">约定</span>（convention），这些约定无所谓真假，仅仅是出于方便才提出来的。约定论行走于经验论和唯理论之间，一方面认为约定不是凭空产生的，而是受经验的引导或提示；另一方面认为约定是人类自由创造的产物。在一定程度上，庞加莱也赞同康德的先验论，认为一些算术公理是先天综合判断，但同时也认为欧氏几何公理仅仅是约定（否则无法解释非欧几何的合理性），并非康德所坚信的绝对真理。相比康德主张的人为自然立法，庞加莱主张的是人为科学立法。他提出，一个被反复验证过的规律可以通过约定从定律提升到原理，从此不再接受实验的检验，成为永恒的严格的真命题<a class="link" href="#note1"><sup>[1]</sup></a>——这就部分地解释了被我们一再质疑的精确公式的合理性。一个适当选择的原理虽然牺牲了客观性，但却能给科学研究带来极大的便利。比如，牛顿第二运动定律（F=ma）可以提升为原理（比如作为力或质量的定义），成为力、质量和加速度之间的永恒关系。正是基于这种思想，他建议将光速不变作为公设，因而被爱因斯坦尊为相对论的先驱。约定并不是假设的全部，庞加莱把科学假设细分为三类——
        </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p class="simpara">自然假设（natural hypothesis）</p><p>
                    这是一类极其自然且难以避免的假设，实质上是伪装的定义或约定。比如超距无关性假设：相距较远的两个物体之间互相独立。显而易见，没有这一假设任何实验都无法开展。比如因果连续性假设：微小的扰动导致的后果也是微小的。这保证了实验者对物体的稳定性和测量误差有一定的容忍度。再比如线性假设：路径在微小的范围可用直线段代替（回忆一下用多边形周长逼近圆周长）。不到万不得已人们是不会舍弃自然假设的，当然也不是没有例外——超距无关性假设在黑洞附近完全失效，量子力学和混沌学动摇了因果连续性假设，而<span class="term">分形</span>（fractal）的出现则破坏了线性假设（参考一个事实：英国海岸线是无限长的）。
                </p></li><li class="listitem"><p class="simpara">中性假设（indifferent hypothesis）</p><p>
                    这类假设是辅助性的、没有客观倾向性的，即使换成其他假设也不会影响结论。之所以选择一个而不是另一个，完全是为了方便计算或有助于理解具体问题。比如我们可以假设物体是连续的，也可以假设是由原子构成的（不连续的）。只要不被误解，它们都是有益无害的。
                </p></li><li class="listitem"><p class="simpara">概括假设（generalization）</p><p>
                    这类假设是概括的经验性假设，随时接受客观实验的证实或证伪。
                </p></li></ul></div><p>
            还有一点值得注意，科学都建立于数学之上，而数学又建立在公理之上。所谓公理，无非是一些公认的却又无法证明的命题，本质上也是人为的设定。从这个角度看，科学也是离不开假设的。有人会反驳，数学公理虽然无法被证明，却是不证自明的。可惜随着非欧几何的横空出世，此言不攻自破。
        </p><p>
            实证主义，尤其是<span class="term">逻辑实证主义</span>（logical positivism或neo-positivism）主张把<span class="term">形而上学</span>（metaphysics）从科学中彻底排除，以捍卫科学的纯粹性。然而，由于科学与假设之间千丝万缕的联系，注定了这种努力是徒劳的。况且，对客观世界可知性的假设不正是一个地地道道的形而上学问题吗？
        </p></div><div class="section" title="注释"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>注释</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    为便于理解这一观点，不妨假设某定律阐述的是事实A与事实B之间的关系。可以引入一个抽象的中介事实C，使之与A之间有一个严格的、精确的、永恒的关系，即所谓的约定性原理。假如以后A与B之间的关系需要修正，只需调整B与C之间的关系即可，不影响A与C之间的恒定关系。
                </p></li></ol></div></div></div>

<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2010%2F04%2F19%2Fhard-thinking-and-soft-thinking-1%2F&amp;linkname=%E8%AE%BA%E6%80%9D%E7%BB%B4%E7%9A%84%E5%88%9A%E6%80%A7%E4%B8%8E%E6%9F%94%E6%80%A7%EF%BC%88%E7%A7%91%E5%AD%A6%E7%9A%84%E8%BF%B7%E4%BF%A1-%E4%B8%8A%EF%BC%89">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2010/04/19/hard-thinking-and-soft-thinking-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>论思维的刚性与柔性（前言）</title>
		<link>http://blog.zhenghui.org/2010/04/02/hard-thinking-and-soft-thinking-0/</link>
		<comments>http://blog.zhenghui.org/2010/04/02/hard-thinking-and-soft-thinking-0/#comments</comments>
		<pubDate>Fri, 02 Apr 2010 10:04:33 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[思维]]></category>
		<category><![CDATA[刚性思维]]></category>
		<category><![CDATA[柔性思维]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=671</guid>
		<description><![CDATA[<b>论思维的刚性与柔性</b>——前言<br/>
为什么要写这篇文章？]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">论思维的刚性与柔性（前言）</span></h1>

<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/article.css" type="text/css"></head>
<!-- below comes from generated html -->   
 <div lang="zh-CN" class="article" title="论思维的刚性与柔性"><div class="titlepage"><div><div><div class="author"><h3 class="author">郑晖</h3></div></div></div><hr /></div><div class="section" title="前言"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="content"></a>前言</h2></div></div></div><p>
            尊敬的读者，您会认同以下哪些说法呢？
        </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">科学的发现靠的都是逻辑思维。</li><li class="listitem">不存在脱离语言的思维。</li><li class="listitem">科学完全建立在事实之上，是客观而精确的。</li><li class="listitem">一切科学真理终将被发现，也一定能被证明。</li><li class="listitem">有因必有果、有果必有因。</li><li class="listitem">科学=真理、宗教=迷信、非科学=伪科学。</li><li class="listitem">             唯心论是幼稚的、形而上学是僵化的、不可知论是愚昧的，只有唯物辩证法是正确的。</li><li class="listitem">哲学总能指导科学。</li><li class="listitem">宗教总是阻碍科学的发展。</li><li class="listitem">上帝没有藏身之所，人类是宇宙中最智慧的生物。</li><li class="listitem">Marxism是一门科学。</li><li class="listitem">中医、气功、特异功能等都是伪科学。</li><li class="listitem">中国的科技水平在古代是世界领先的，只是在近代才开始落后了。</li><li class="listitem">时间是均匀流逝的、与空间和物质无关的。</li><li class="listitem">空间是连续的、三维的、平直的、无界的、与时间和物质无关的。</li></ol></div><p>
            假如您赞同以上某些观点，您将是我意料之中的读者；假如您反对以上所有观点，您将是我意料之外的知音。下面的问题或许更现实、更有趣些——
        </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">电脑会全面超过人脑吗？</li><li class="listitem">牛顿被落地的苹果砸过吗？</li><li class="listitem">中国人的数学比美国人强吗？</li><li class="listitem">中国人为什么难以避免中式英语？</li><li class="listitem">应试教育和文理分科的弊端在哪里？</li><li class="listitem">勤定能补拙吗？</li><li class="listitem">智商测试可靠吗？</li><li class="listitem">脑筋急转弯能训练思维吗？</li><li class="listitem">如何培养幽默感？</li><li class="listitem">网络上为什么充满了“牛逼”、“傻逼”、“装逼”这类字眼？</li><li class="listitem">为什么网络争论通常是无效的？</li></ol></div><p>
            您一定会问：一篇文章有可能解决这么多的问题吗？它们之间又有什么必然的联系呢？正所谓醉翁之意不在酒，本文的重点也不在于解决这一堆难题，而在于提出一种“<span class="strong"><strong>刚柔思维</strong></span>”的观点。这当然不是在翻版国产的<span class="term">阴阳思维</span>或舶来的<span class="term">辩证思维</span>，主人的手艺再差，也不会靠炒冷饭来招待客人的。如果说后二者是看待事物的二分法——阴与阳、矛与盾，那么前者便是思维方式的二分法——刚性思维与柔性思维。换言之，后二者关注的是<span class="strong"><strong>事物的正反两面</strong></span>，而前者关注的是<span class="strong"><strong>思维的上下两层</strong></span>。
        </p><p>
            为阐明观点起见，本文将涉及多种学科和领域。如果您对某些方面知之甚少，不必望而却步。请记住，它们只是辅助论据，并非核心论题。容忍自己的无知，正是柔性思维的一种表现。如果您是某些方面的专家，慧眼识出文中谬误，也不必拂袖而去。别忘了，错误的论证并不必然导出错误的结论。容忍他人的无知，同样是柔性思维的一种表现。
        </p><p>
            本人在数学和计算机领域尚知一二，在其他领域则未知万一。以微薄之才而论天地之道、心灵之术，何啻以升量石。每念至此，不胜惶惑，情知贻笑大方事小、贻误后学事大。特于文后详列文献出处，以供读者参阅，或可稍安惴惴之心。然则如此，文中话题无不敏感，观点无不鲜明，结论无不坚定。或有人问：这般前后不一，岂非貌恭实倨、虚伪之至？其实不然。敬畏未知，怀疑已知，非此则无以广博，是为思维之柔；不惧未知，坚信已知，非此则无以精深，是为思维之刚（疑似坠入辩证法的泥淖）。思维之法，自当刚柔并济，文中要旨即在于此。欲知刚柔之义、刚柔之用，且听下回分解。
        </p><p>
        </p></div><div class="section" title="附言"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>附言</h2></div></div></div><p>
            该文的成因可一言蔽之：久积于心，不吐不快。用计算机的语言来说：它是为防止大脑内存过载（memory overload）而将部分想法序列化为语言（serialization）、持久化为文字（persistence）最终形成的一个快照（snapshot）。之所以选择开源（open source），是希望能对他人有所裨益。除此之外，别无他意，亦无他求。为避自命高深或故作矫情之嫌，并免无谓口舌之争，后续文章将关闭评论（参见问题：为什么网络争论通常是无效的？）。用恶俗得令人倒胃的流行网语来说：本人既不牛逼，也不傻逼，更不装逼。拒不相信者，请打道回府；有心赐教者，请在此<a class="link" href="http://blog.zhenghui.org/contact/" target="_top">留言</a>；由衷赞赏者，请五星相赠（本博客支持评分机制）；鄙视不屑者，请一分示嘲（很抱歉没有提供零分或负分）。
        </p><p>
            文中“刚性思维”与“柔性思维”的提法不幸与某些文章撞车，好在只是名称上的冲突，内涵并不相同。特此说明。
        </p></div><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2010%2F04%2F02%2Fhard-thinking-and-soft-thinking-0%2F&amp;linkname=%E8%AE%BA%E6%80%9D%E7%BB%B4%E7%9A%84%E5%88%9A%E6%80%A7%E4%B8%8E%E6%9F%94%E6%80%A7%EF%BC%88%E5%89%8D%E8%A8%80%EF%BC%89">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2010/04/02/hard-thinking-and-soft-thinking-0/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>《冒号课堂》在台湾上市</title>
		<link>http://blog.zhenghui.org/2010/03/10/colonclass-sales-tw/</link>
		<comments>http://blog.zhenghui.org/2010/03/10/colonclass-sales-tw/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 03:14:53 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[上市]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=644</guid>
		<description><![CDATA[公告：《冒号课堂》今起在台湾上市]]></description>
			<content:encoded><![CDATA[
<h2><strong>公告</strong>：《冒号课堂》今起在台湾上市。</h2>
<p>&nbsp;</p>

<p><strong>基本信息</strong>：</p>
<div><img src="http://blog.zhenghui.org/img/colonclass/bookcover-tw.jpg" alt="" /></div>
<p>书名：程式設計範式與OOP的思考術：冒號老師的十三堂課</p>
<p>作者：鄭暉</p>
<p>书号：9789862013090</p>
<p>出版社：<a href="http://www.drmaster.com.tw/Bookinfo.asp?BookID=PG20288">博碩文化股份有限公司</a></p>
<p>出版日期：2010年03月10日</p>
<p>定价：NT$490</p>
<p>页码：496</p>
<p>规格：17*23</p>
<p>语言：中文/繁體</p>
<p>&nbsp;</p>

<p><strong>网站主页：</strong></p>
<p>博客：<a href="http://blog.zhenghui.org/">http://blog.zhenghui.org/</a></p>
<p>豆瓣：<a href="http://www.douban.com/subject/4031906/">http://www.douban.com/subject/4031906/</a></p>
<p>&nbsp;</p>

<p><strong>网上书店</strong>：</p>
<p>博客來網路書店：  <a href="http://www.books.com.tw/exep/prod/booksfile.php?item=0010462958">http://www.books.com.tw/exep/prod/booksfile.php?item=0010462958</a></p>
<p>誠品網路書店：<a href="http://www.eslite.com/product.aspx?pgid=1001120321928546&amp;cate=156&amp;sub=212">http://www.eslite.com/product.aspx?pgid=1001120321928546&amp;cate=156&amp;sub=212</a></p>
<p>天瓏網路書店：<a href="https://tlsj.tenlong.com.tw/WebModule/BookSearch/bookSearchViewAction.do?isbn=9789862013090&amp;sid=55495">https://tlsj.tenlong.com.tw/WebModule/BookSearch/bookSearchViewAction.do?isbn=9789862013090&amp;sid=55495</a></p>
<p>金石堂網路書店：<a href="http://books.yam.com/book/Book_Page.asp?ActId=future&amp;LID=1109&amp;KMCode=2014713210920">http://books.yam.com/book/Book_Page.asp?ActId=future&amp;LID=1109&amp;KMCode=2014713210920</a></p>
<p>金石堂網路書店：<a href="http://www.kingstone.com.tw/book/book_page.asp?LID=se008&amp;kmcode=2014713210920&amp;Actid=wise">http://www.kingstone.com.tw/book/book_page.asp?LID=se008&amp;kmcode=2014713210920&amp;Actid=wise</a></p>
<p>三民網路書店：<a href="http://www.sanmin.com.tw/page-product.asp?pf_id=99D155e9w102s87g103V70u111l129uOFfJOi1060LoB">http://www.sanmin.com.tw/page-product.asp?pf_id=99D155e9w102s87g103V70u111l129uOFfJOi1060LoB</a></p>
<p>華通書坊：<a href="http://www.huatung.com/index.php?PHP_action=view_book&amp;PHP_bookid=6qe9ml5wj9pm7qj3ck616291268305819">http://www.huatung.com/index.php?PHP_action=view_book&amp;PHP_bookid=6qe9ml5wj9pm7qj3ck616291268305819</a></p>
<p>法錸城網路書店：<a href="http://www.flytownbooks.com/itemdesc.asp?ProductID=PG20288">http://www.flytownbooks.com/itemdesc.asp?ProductID=PG20288</a></p>
<p>益大資訊：<a href="http://etaitbook08.pixnet.net/blog/post/30557874">http://etaitbook08.pixnet.net/blog/post/30557874</a></p>
<p>3dWoo電腦書店：<a href="http://www.3dwoo.com/showBookDetail.asp?nb=25377">http://www.3dwoo.com/showBookDetail.asp?nb=25377</a></p>
<p>華文網網路書店：<a href="http://www.book4u.com.tw/book_Detail.asp?goods_ser=kk0263881">http://www.book4u.com.tw/book_Detail.asp?goods_ser=kk0263881</a></p>
<p>&nbsp;</p>

<p>CP1897.com商務網上書店（香港）：<a href="http://www.cp1897.com.hk/product_info.php?BookId=9789862013090">http://www.cp1897.com.hk/product_info.php?BookId=9789862013090</a></p>
<p>&nbsp;</p>

<p><strong>各地书店</strong>：</p>
<p><a href="http://www.drmaster.com.tw/service-03.asp">http://www.drmaster.com.tw/service-03.asp</a></p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2010%2F03%2F10%2Fcolonclass-sales-tw%2F&amp;linkname=%E3%80%8A%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%E3%80%8B%E5%9C%A8%E5%8F%B0%E6%B9%BE%E4%B8%8A%E5%B8%82">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2010/03/10/colonclass-sales-tw/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>《冒号论坛》开放</title>
		<link>http://blog.zhenghui.org/2010/01/01/colonclass-bbs-openning/</link>
		<comments>http://blog.zhenghui.org/2010/01/01/colonclass-bbs-openning/#comments</comments>
		<pubDate>Fri, 01 Jan 2010 03:10:51 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[冒号论坛]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=625</guid>
		<description><![CDATA[公告：本博新开《冒号论坛》，欢迎赏光！]]></description>
			<content:encoded><![CDATA[<h2 style="text-align: center;">致读者</h2>
<div>
<p>值此新年到来之际，本博特开辟<a href="http://bbs.zhenghui.org">冒号论坛</a>，欢迎各位赏光！</p>
<p>目前论坛上已开设一个主讨论区（forum）：<a href="http://bbs.zhenghui.org/forum/colonclass-discussion">《冒号课堂》讨论区</a>，用于<a href="http://www.douban.com/subject/4031906/">《冒号课堂——编程范式与OOP思想》</a>的作者和读者之间的交流，包括回复读者对书中的疑问、方便读者给本书提意见或建议等等。根据需要，今后也可能开设其他的讨论区。</p>
<p>稍有不便的是，您需要登录才能在该论坛回帖或开帖。好在手续极其简单，您只需在论坛上方点击<a href="http://bbs.zhenghui.org/register.php">Register</a>，填写一个用户名和email地址即可登记成功。不久您会收到一封email，里面有您的密码，凭此便可登录论坛。第一次登录后，您可以点击自己的用户名，修改密码和个人信息。如果您对某个讨论（forum）或话题（topic）感兴趣，可以订阅相应的RSS。另一个附带的好处是，该论坛与博客是集成的，登录论坛即可登录博客（反之亦然），这样在博客上回帖时就不必再输入个人信息了。如果您在登录时遇到困难，请在此帖留言。多谢您的合作！</p>
</div>
<div>
<p style="text-align: right;">郑晖</p>
<p style="text-align: right;">2010年1月1日</p>
</div>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2010%2F01%2F01%2Fcolonclass-bbs-openning%2F&amp;linkname=%E3%80%8A%E5%86%92%E5%8F%B7%E8%AE%BA%E5%9D%9B%E3%80%8B%E5%BC%80%E6%94%BE">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2010/01/01/colonclass-bbs-openning/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>《冒号课堂》意见收集</title>
		<link>http://blog.zhenghui.org/2009/11/07/colonclass-suggestions/</link>
		<comments>http://blog.zhenghui.org/2009/11/07/colonclass-suggestions/#comments</comments>
		<pubDate>Sat, 07 Nov 2009 07:48:18 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=549</guid>
		<description><![CDATA[征求对《冒号课堂》一书的问题、意见和建议]]></description>
			<content:encoded><![CDATA[<h2 style="text-align: center;">致读者</h2>
<div>
<p>《冒号课堂》业已<a href="http://blog.zhenghui.org/2009/10/26/colonclass-sales/">上市</a>，如果您在本书中发现任何谬误或疑问，或对本书有任何意见或建议，敬请回复此帖。小至标点符号，大至思想观点，但凡有疑，尽可畅所欲言，笔者将不胜感谢！</p>
<p>本着对读者负责的精神，若发现书中错误，本博将及时勘正；若发现不够详尽之处，本博将另行补充。</p>
</div>
<div>
<p style="text-align: right;">郑晖</p>
<p style="text-align: right;">2009年11月7日</p>
</div>
<p><strong>后记</strong>：</p>
<p>本帖已成<em>deprecated</em> API，<em>不建议</em>读者继续在此回复。对本书如有疑问或建议，请移步<a href="http://bbs.zhenghui.org/">冒号论坛</a>。</p> 
 <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F11%2F07%2Fcolonclass-suggestions%2F&amp;linkname=%E3%80%8A%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%E3%80%8B%E6%84%8F%E8%A7%81%E6%94%B6%E9%9B%86">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/11/07/colonclass-suggestions/feed/</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>《冒号课堂》上市</title>
		<link>http://blog.zhenghui.org/2009/10/26/colonclass-sales/</link>
		<comments>http://blog.zhenghui.org/2009/10/26/colonclass-sales/#comments</comments>
		<pubDate>Mon, 26 Oct 2009 03:44:41 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[上市]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=527</guid>
		<description><![CDATA[公告：《冒号课堂》已正式上市]]></description>
			<content:encoded><![CDATA[
<h2><strong>公告</strong>：《冒号课堂》已正式上市。</h2>
<p>&nbsp;</p>

<p><strong>基本信息</strong>：</p>
<div style="float: left; padding-right: 5px;"><img src="http://blog.zhenghui.org/img/colonclass/bookcover_3D_small.jpg" alt="" /></div>
<p>书名：冒号课堂——编程范式与OOP思想</p>
<p>书号：978-7-121-09545-0</p>
<p>出版社： 电子工业出版社</p>
<p>出版日期：2009年10月</p>
<p>字数：570千字</p>
<p>定价：￥65.00</p>
<p>页码：476</p>
<p>开本：16</p>
<p>&nbsp;</p>

<p><strong><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">网站主页：</span></strong></p>
<p>博客：<a href="http://blog.zhenghui.org/">http://blog.zhenghui.org/</a></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">豆瓣：<a href="http://www.douban.com/subject/4031906/">http://www.douban.com/subject/4031906/</a></span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">51CTO读书频道：<a href="http://book.51cto.com/art/200910/155991.htm">http://book.51cto.com/art/200910/155991.htm</a></span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;"><br /></span></span></p>
<p><strong>网上书店</strong>：</p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">互动网：<a href="http://www.china-pub.com/196068">http://www.china-pub.com/196068</a></span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">当当网：<a href="http://product.dangdang.com/product.aspx?product_id=20707892">http://product.dangdang.com/product.aspx?product_id=20707892</a></span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">卓越网：<a href="http://www.amazon.cn/detail/product.asp?prodid=bkbk992557">http://www.amazon.cn/detail/product.asp?prodid=bkbk992557</a> </span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">北发图书网：<a href="http://book.beifabook.com/product/BookDetail.aspx?Plucode=712109545">http://book.beifabook.com/product/BookDetail.aspx?Plucode=712109545</a> </span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">新华书店.com：<a href="http://www.xinhuabookstore.com/product/1252467/">http://www.xinhuabookstore.com/product/1252467/</a></span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">金桥书城：<a href="http://book.jqcq.com/product/1310853.html">http://book.jqcq.com/product/1310853.html</a> </span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">电子工业出版社：<a href="http://www.phei.com.cn/bookshop/bookinfo.asp?booktype=main&amp;bookcode=TP095450">http://www.phei.com.cn/bookshop/bookinfo.asp?booktype=main&amp;bookcode=TP095450</a></span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">中国图书网：<a href="http://www.bookschina.com/4344485.htm">http://www.bookschina.com/4344485.htm</a></span></span></p>
<p><span style="color: #000000;"><span style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,&amp;quot;Bitstream Charter&amp;quot;,Times,serif;">99网上书城：<a href="http://www.99read.com/product/detail.aspx?proid=541928">http://www.99read.com/product/detail.aspx?proid=541928</a><br /></span></span></p>
<p>华储网：<a href="http://www.huachu.com.cn/itbook/bookinfo.asp?lbbh=10110053">http://www.huachu.com.cn/itbook/bookinfo.asp?lbbh=10110053</a></p>
<p>新风雨：<a href="http://www.cnforyou.com/query/bookdetail1.asp?viBookCode=6625">http://www.cnforyou.com/query/bookdetail1.asp?viBookCode=6625</a></p>
<p>拓普网：<a href="http://www.toopoo.com/cmml/cmmlwb/query/query_info_det.asp?sdh=1138291">http://www.toopoo.com/cmml/cmmlwb/query/query_info_det.asp?sdh=1138291</a></p>
<p>百度有啊：<a href="http://youa.baidu.com/item/42141d9fcd0e3a9696ea5021">http://youa.baidu.com/item/42141d9fcd0e3a9696ea5021</a></p>
<p>儒商书库：<a href="http://www.sijibook.com/BookDetails.aspx?bookid=135505">http://www.sijibook.com/BookDetails.aspx?bookid=135505</a></p>
<p>金书网：<a href="http://www.golden-book.com/booksinfo/12/1200741.html">http://www.golden-book.com/booksinfo/12/1200741.html</a></p>
<p>蔚蓝网：<a href="http://www.wl.cn/5951937">http://www.wl.cn/5951937</a></p>
<p>中教图书：<a href="http://www.book1993.com/pro-821338.html">http://www.book1993.com/pro-821338.html</a></p>
<p>ANI图书网：<a href="http://www.anibook.cn/ProductDetail/2009/10/27/PBA97871210954500001.html">http://www.anibook.cn/ProductDetail/2009/10/27/PBA97871210954500001.html</a></p>
<p>希望书店：<a href="http://www.hopebook.net/tushumulu/301117/">http://www.hopebook.net/tushumulu/301117/</a></p>
<p>拍拍网：<a href="http://auction1.paipai.com/2419A70400000000002438DF0568A984">http://auction1.paipai.com/2419A70400000000002438DF0568A984</a></p>
<p>天下书城：<a href="http://book110.cn/bookshow/200911/442565/">http://book110.cn/bookshow/200911/442565/</a></p>
<p>广购中心：<a href="http://www.gzbookcenter.com/search/view.jsp?proID=1214051">http://www.gzbookcenter.com/search/view.jsp?proID=1214051</a></p>
<p>&nbsp;</p>

<p><strong>全国各地书店有售</strong></p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px;">
<table border="0" cellspacing="1" cellpadding="1" width="100%">
<tbody>
<tr>
<td height="25" valign="bottom" bgcolor="#fbf9f5"><strong>字数：</strong>570千字</td>
<td width="21%" height="25" valign="bottom" bgcolor="#fbf9f5"></td>
<td width="36%" valign="bottom" bgcolor="#fbf9f5"><strong>定价：</strong>￥65.00元</td>
</tr>
<tr>
<td align="center" valign="top"></td>
<td width="19%" height="25" valign="bottom" bgcolor="#fbf9f5"><strong>页码：</strong>476</td>
<td valign="bottom" bgcolor="#fbf9f5"></td>
<td valign="bottom" bgcolor="#fbf9f5"><strong><span style="color: #ff0000;">会员价：</span></strong><span style="color: #ff0000;">￥52.00元</span></td>
</tr>
<tr>
<td align="center" valign="top"></td>
<td height="25" valign="bottom" bgcolor="#fbf9f5"><strong>开本：</strong>16</td>
</tr>
</tbody></table>
</div>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F10%2F26%2Fcolonclass-sales%2F&amp;linkname=%E3%80%8A%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%E3%80%8B%E4%B8%8A%E5%B8%82">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/10/26/colonclass-sales/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>冒号课堂§10.2：抽象类型</title>
		<link>http://blog.zhenghui.org/2009/10/24/colon-class-10_2/</link>
		<comments>http://blog.zhenghui.org/2009/10/24/colon-class-10_2/#comments</comments>
		<pubDate>Sat, 24 Oct 2009 01:37:53 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[mixin]]></category>
		<category><![CDATA[trait]]></category>
		<category><![CDATA[抽象数据类型]]></category>
		<category><![CDATA[抽象类]]></category>
		<category><![CDATA[抽象类型]]></category>
		<category><![CDATA[接口]]></category>
		<category><![CDATA[继承]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=518</guid>
		<description><![CDATA[<b>抽象类型</b>——实中之虚（<em>介绍抽象类型的种类、意义及其用法</em>）<br/>
•	浅显的比方只是门槛前的台阶，借之或可拾级入门，却无法登堂入室<br/>
•	具体类型是创建对象的模板，抽象类型是创建类型的模块<br/>
•	抽象数据类型的核心是数据抽象，而抽象类型的核心是多态抽象<br/>
•	必先以术养道，而后以道御术<br/>
•	以社会身份而非个人身份作为公民之间联系的纽带，正是针对接口而非实现来编程的社会现实版<br/>
•	个体身份对应的规范抽象借助封装，以数据抽象的形式出现<br/>
•	家庭身份对应的规范抽象借助继承，以类型层级的形式出现<br/>
•	社会身份对应的规范抽象借助多态，以多态抽象的形式出现]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第十课 多态机制（2）</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="抽象类型"><div class="titlepage"><div><div><h1 class="title"><a name="id603878"></a>抽象类型——实中之虚</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>介绍抽象类型的种类、意义及其用法</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>有无相生，难易相成</p></div><div class="attribution"><span>—<span class="attribution">《老子•道经》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    浅显的比方只是门槛前的台阶，借之或可拾级入门，却无法登堂入室
                </p></li><li class="listitem"><p>
                    具体类型是创建对象的模板，抽象类型是创建类型的模块
                </p></li><li class="listitem"><p>
                    抽象数据类型的核心是数据抽象，而抽象类型的核心是多态抽象
                </p></li><li class="listitem"><p>
                    必先以术养道，而后以道御术
                </p></li><li class="listitem"><p>
                    以社会身份而非个人身份作为公民之间联系的纽带，正是针对接口而非实现来编程的社会现实版
                </p></li><li class="listitem"><p>
                    个体身份对应的规范抽象借助封装，以数据抽象的形式出现
                </p></li><li class="listitem"><p>
                    家庭身份对应的规范抽象借助继承，以类型层级的形式出现
                </p></li><li class="listitem"><p>
                    社会身份对应的规范抽象借助多态，以多态抽象的形式出现
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>具体类型与抽象类型的区别是什么？</p></li><li class="listitem"><p>抽象数据类型与抽象类型的区别是什么？</p></li><li class="listitem"><p>除接口与抽象类外还有其他抽象类型吗？它们有何特点和意义？</p></li><li class="listitem"><p>抽象类型的主要作用是什么？</p></li><li class="listitem"><p>在系统中应采用何种类型作为模块之间通讯的数据类型？</p></li><li class="listitem"><p>接口是为了克服（Java或C#中）抽象类不能多重继承的缺点吗？</p></li><li class="listitem"><p>接口与抽象类在语法和语义上各有什么不同？</p></li><li class="listitem"><p>标记接口有何作用？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            冒号调整了焦点：“鉴于目前专注的范式是OOP，参数多态最好放在以后的GP专题再作探讨。除非特别说明，下面提到的多态专指子类型多态。谈到这类多态，就不得不提及抽象类型。谁来说说，究竟什么是抽象类型？”
        </p><p>
            冒号抬手内扬，摆出了对练的姿势。
        </p><p>
            叹号率先抢攻：“抽象类型指的是至少含有一个抽象方法的类型。”
        </p><p>
            冒号轻松化解：“在C++中这句话尚可勉强成立，但在Java和C#中则大不尽然：一个类即使没有一个抽象方法也可以被申明为抽象的；一个没有任何成员的空接口或称<span class="term">标记接口</span>同样属于抽象类型。”
        </p><p>
            “抽象类型是指无法实例化的类型。”逗号发起二次进攻。
        </p><p>
            冒号见招拆招：“Java中的Math类也不能实例化，原因是它只有private构造器，并且没有一个能返回实例的静态方法。C#中的Math类是静态类，同样不能实例化。”
        </p><p>
            问号纵身而上：“抽象类型指能且只能通过继承来实例化的类型。Math类是final类，无法被继承。最主要的是，它的价值体现在它的静态方法上，压根儿就没有实例化的必要。”
        </p><p>
            冒号借力反打：“为什么要强调无法实例化呢？”
        </p><p>
            引号一旁助攻：“一个抽象类型代表着一个抽象概念，而抽象概念自然是无法具化的。比如你无法实例化抽象的形状，但可以实例化长方形、三角形等具体的形状；无法实例化抽象的水果，但可以实例化苹果、桔子等具体的水果。”
        </p><p>
            “很官方的说法。这就好比将继承关系说成‘is-a’关系一样，理论上虽通俗易懂，实践上却不足为训。”冒号收起架势，“要说抽象，Java和C#中的Object类可谓包罗万象，该够抽象了吧？不照样实例化？<span class="term">列表</span>（list）与<span class="term">映射</span>（map）是抽象的还是具体的？在C++中它们是具体类型，而在Java和C#中它们却是抽象类型<a class="link" href="#note1"><sup>[1]</sup></a>。这又是为什么？”
        </p><p>
            一连串的反问让大家陷入沉思。
        </p><p>
            “相比其他编程范式，OOP更贴合客观世界，人们经常用打比方的形式来描述和理解OOP的一些概念和思想。这本身并无不妥，但一定要保持清醒的头脑：浅显的比方只是门槛前的台阶，借之或可拾级入门，却无法登堂入室。”冒号谆戒道，“天下之理皆同，天下之人皆同，故凡学问殿堂之前皆一般景象：入门者众，入室者寡。本班的目的便是，引导诸位从徘徊于编程之门左右的人群中越众而出，早达内室。”
        </p><p>
            “那就成了传说中的内室弟子吧？大伙在门边转悠很久了，头都发晕了，师父还是快些领我等入室吧。” 逗号近乎戏谑地恳求。
        </p><p>
            冒号一笑：“我可算不得你们的师父，只不过是个闻道在先的师兄而已。”
        </p><p>
            一直没有出手的句号忽然开腔：“抽象是个相对概念，一个类型是否是抽象的完全取决于设计者对它的角色定位。如果想用它来创建对象，它就是可实例化的具体类型；如果想用它来作为其他类型的基类，它就是不可实例化的抽象类型。”
        </p><p>
            “这才击中了要害！”冒号不禁喝彩道，“整理一下你的观点：<span class="strong"><strong>具体类型是创建对象的模板，抽象类型是创建类型的模块</strong></span>。一个是为对象服务的，一个是为类型服务的。显然，后者的抽象性正是源自其服务对象的抽象性。就拿刚才的实例来说，模板方法模式中的Authenticator类是抽象的，是为创建子类型SimpleAuthenticator、Sha1Authenticator等服务的；策略模式中的Authenticator类是具体的，是为创建对象服务的，但它合成的两个接口KeyValueKeeper和Encrypter又是为创建算法类型服务的。值得注意的是，不要把抽象类型与抽象数据类型（ADT）混为一谈，后者的抽象指的是类型的接口不依赖其实现。或者说，<span class="strong"><strong>抽象数据类型的核心是数据抽象，而抽象类型<a class="link" href="#note2"><sup>[2]</sup></a>的核心是多态抽象</strong></span>。”
        </p><p>
            问号想让概念更明确些：“抽象类型就只有<span class="term">接口</span>（interface）和<span class="term">抽象类</span>（abstract class）两种吗？”
        </p><p>
            “在Java和C#中基本上是这样，但在C++中这两种类型没有显式的区别<a class="link" href="#note3"><sup>[3]</sup></a>。”冒号，“此外，动态OOP语言如Ruby、Python、Perl、Scala、Smalltalk等还至少支持mixin和trait中的一种类型。mixin直译为‘混入’，trait直译为‘特质’，为避免翻译上的问题，今后我们还是采用英文术语。这两种类型大同小异，为简便起见，下面以mixin类型为代表<a class="link" href="#note4"><sup>[4]</sup></a>。它们的出现是为了弥补接口与抽象类的一些不足，更好地实现代码重用。我们知道，接口的主要目的是创建多态类型，本身不含任何实现。子类型通过接口继承只能让代码被重用，却无法重用超类型的实现代码。抽象类可以重用代码，可又有多重继承的问题。Java和C#不支持这种机制，C++虽支持但有不少弊端。”
        </p><p>
            引号奇道：“这个问题上节课不是已经解决了吗？用合成来代替继承啊。”
        </p><p>
            冒号解释：“合成是一种解决办法，但也不是没有缺陷。首先，合成的用法不如继承那么简便优雅，这也是许多人喜欢用继承的主要原因；其次，合成不能产生子类型，而有时这正是设计者所需要的；再次，合成无法覆盖基础类的方法，也无法访问它的protected成员；最后，却可能是最大的缺点是：合成的基础类只能是具体类型，不能是抽象类型<a class="link" href="#note5"><sup>[5]</sup></a>。”
        </p><p>
            逗号不明所以：“这能算是缺点吗？”
        </p><p>
            “如前所述，具体类型的主要任务是<span class="emphasis"><em>创造新对象</em></span>，如果用作合成或继承的基础类，等于是又承担了原本抽象类型的任务——<span class="emphasis"><em>创造新类型</em></span>。这不仅有越俎代庖之嫌，而且这两个任务往往也是冲突的。我们曾提出，一个类的服务应该有纯粹性和完备性。一方面，人们希望创造的新对象无所不能，因此更看重服务的<span class="emphasis"><em>完备性</em></span>，倾向它包含尽可能多的功能；另一方面，人们又希望创造的新类型有所不依，因此更看重服务的<span class="emphasis"><em>纯粹性</em></span>，倾向它包含尽可能少的功能。”冒号擘肌分理，“妥协的结果是，一个新类型往往只用到基础类型的部分功能，却可能受到其他功能变动的影响。虽然这种影响在良好的封装之下会大大削弱，但也难以完全消弭。”
        </p><p>
            句号思索片刻，已明其意：“换句话说，以具体类型为代码重用的基本单位，难免颗粒度过大？”
        </p><p>
            “然也！”冒号的手在空中挽了个花，“其实作为抽象类型的接口也有类似的尴尬：对它的客户类来说，它承诺的服务是多多益善；对它的实现类来说，承诺越多负担却越重。如果能有这样一种可重用的模块，既不像具体类型那样面面俱到，又不像接口那样有名无实，也没有抽象类的多重继承之弊，岂不妙哉？”
        </p><p>
            “想必就是mixin了！”叹号眼中闪过一道光芒，旋即又暗淡下来，“只可惜Java并不支持啊。”。
        </p><p>
            “Java不支持就没兴趣了？” 冒号听出他的话里有话，“要成为优秀的程序员，千万不能画地为牢、自我禁锢。始终要保持一颗开放的心，不要拘于某些语言或范式，也不要囿于某些概念或技术。”
        </p><p>
            叹号的耳根有点发热。
        </p><p>
            “陌生的理论和技术开始总是拒人千里，不过一旦你了解其问题来源，它们会慢慢变得和蔼可亲起来。”冒号循循善诱，“既然具体类型和现存的两种抽象类型均有不足之处，mixin的产生便合情合理了。它是具体类型与接口类型的一种折衷，既可有抽象方法，也可有具体方法。这一点类似抽象类，但又没有抽象类的多重继承问题。举例来说，Ruby中的Comparable就是一个简单却很典型的mixin。”
        </p><p>
            问号插话：“Java中也有Comparable接口啊。”
        </p><p>
            冒号道出其中差异：“Java中的Comparable和C#中的IComparable只有一个抽象的比较方法，而Ruby中的除了有类似的抽象方法——比较（&lt;=&gt;）之外，还提供了小于（&lt;）、小于等于（&lt;=）、等于（==）、大于（&gt;）、大于等于（&gt;=）和介于（between?）等六种具体方法。显而易见，多出的方法均可通过唯一抽象的比较方法来实现。”
        </p><p>
            引号一点即通：“如此一来，重用Comparable的类只需实现一个抽象方法，便可自动拥有另外六个有用的功能。这既满足了客户类的需求，又不增加实现类的负担。”
        </p><p>
            “买一送六，这买卖划算！”逗号来劲了。
        </p><p>
            冒号双眼微眯：“更划算的买卖是Ruby中Enumerable。任何包含该mixin的类只要实现一个遍历方法each，便可免费得到二十多个有关遍历和搜寻的方法。如果再实现比较方法&lt;=&gt;，还可获赠排序和最值方法。相比Java中Enumeration和Iterator接口，优势历然。”
        </p><p>
            问号很好奇：“为什么称为mixin呢？”
        </p><p>
            冒号述说由来：“冰淇淋中经常会掺混一些薄荷、香草、巧克力之类的调味料和花生、坚果之类的小零碎，人们管它们叫mix-in。后来被借用来表示一种抽象类型，主要有如下特点：一、抽象性和依赖性：本身没有独立存在的意义，必须融入主体类型才能发挥作用；二、实用性和可重用性：不仅提供接口，还提供部分实现；三、专一性和细粒度性：提供的接口职责明确而单一；四、可选性和边缘性：为主体类型提供非核心的辅助功能。”
        </p><p>
            “这些特点与风味添加料还真的颇为神似。”叹号想着想着，嘴里不自觉地咂摸了一下。
        </p><p>
            “虽然C++、Java和C#在语法上尚不支持mixin，但C++可通过多重继承、Java和C#可通过合成和接口来分别模拟mixin。不仅如此，借助<span class="term">切面式编程</span>（AOP），Java和C#甚至可完全实现mixin；借助<span class="term">泛型式编程</span>（GP），C++也能通过<span class="term">模板</span>更好地实现mixin<a class="link" href="#note6"><sup>[6]</sup></a>。”冒号点到为止，“就此我们重温前面提到的两个观点。一是编程范式之间的合作性：mixin属于OOP的范畴，但其他编程范式如切面式、泛型式以及二者背后的元编程都能与之相通；二是设计与语言的相关性：C++、Java和C#以及其他诸如Ruby、Python等动态语言对mixin有着不同的支持方式，这在一定程度上会影响系统的OOP设计。”
        </p><p>
            引号憧憬道：“语言是在发展的，说不定哪天Java也会支持mixin的。”
        </p><p>
            冒号以实相应：“Java的动态小兄弟Groovy在1.6版已经开始支持mixin ，而C#3.0也新引入了对mixin更友好的语法特性<a class="link" href="#note7"><sup>[7]</sup></a>。”
        </p><p>
            逗号提了一个长期困惑大家的问题：“每当一个新技术出现，我就觉得很矛盾：不追怕落伍，追吧又怕落空。如何判断一个它是昙花一现，还是大势所趋呢？”
        </p><p>
            “任何技术都是在赞美与批判中成长起来的，预测它们是流星还是恒星绝非易事。就拿OOP来说，上个世纪六十年代就出现了支持OOP的语言<a class="link" href="#note8"><sup>[8]</sup></a>，但直到九十年代中后期它才真正成为主流的编程范式。这段时间恐怕比大多数人的程序员生涯还长吧。再说mixin，其实并非今日的重点，介绍它的目的不是盲目追新，而是希望透过其背后的需求驱动点，重新审视现有技术。至于它今后会不会为主流语言所接纳，反倒不是那么重要了。如果一定要我给个建议，那就是八个字：‘<span class="strong"><strong>不执一法，不舍一法</strong></span>’。”冒号以禅语作答，“软件技术这棵大树经过多年的快速成长，早已枝蔓丛生。欲臻不执不舍之境，当如开班导言中所说：究其根本以知过去，握其主干以知现在，察其生长点以知未来。我之所以倾向于用抽象的方式来谈论技术，正是因为抽象的东西更接近根、更接近干、更接近生长点，从而更普泛深刻，也更稳定持久。”
        </p><p>
            句号借机问道：“您认为抽象比具体更重要？”
        </p><p>
            “抽象与具体无所谓孰高孰低，它们只是功用不同而已。”冒号轻轻晃了晃脑袋，“正所谓：<span class="strong"><strong>必先以术养道，而后以道御术</strong></span>。也就是说，在学习时应注重从具体知识中领悟抽象思想，在应用时应注重用抽象理论来指导具体实践。类似地，软件开发也是如此：从具体需求中构建出抽象模型，再根据抽象模型来完成具体实现。因此，在设计阶段抽象类型尤为关键，而在实现阶段则是具体类型更为重要。”
        </p><p>
            问号表示理解：“假如从具体需求直接跨到具体实现，省去中间的抽象建模过程，那还用得着架构师和分析师吗？”
        </p><p>
            “话虽不错，但疑似倒果为因。”冒号洞若观火，“是否有必要抽象建模，关键看项目需求。如果需求简单而稳定，一步到位又何尝不可？甚至软件的开发效率和运行效率还更高——为劈几根细柴而磨刀，值吗？如果需求复杂而多变，引入抽象方有‘磨刀不误砍柴工’之效。毕竟抽象不是目的而是手段，对它片面的追求反会导致过度的设计。”
        </p><p>
            众人这才发现，给老冒戴顶“抽象派”的帽子是有些冤枉他了，应该是“抽象现实派”的。
        </p><p>
            冒号续道：“为进一步认识抽象类型，我举个非常实用的例子。它只适用于C++，而不适用于Java和C#。如果你对这一点感到遗憾的话，不要忘记我们的原则：具体实例永远是为抽象思想服务的。”
        </p><p>
            幻灯一闪，现出一段C++代码——
        </p><div class="informalexample"><pre class="programlisting">
/** 一个不可复制的类 */
class NonCopyable
{
protected:
    // 非公有构造函数防止创建对象
    NonCopyable() {}  
    // 非公有非虚析构函数建议子类非公有继承
    ~NonCopyable() {}
private: 
    // 私有复制构造函数防止直接的显式复制和通过参数传递的隐式复制
    NonCopyable(const NonCopyable&amp;);
    // 私有赋值运算符防止通过赋值来复制
    const NonCopyable&amp; operator=(const NonCopyable&amp;); // copy assignment
};

/** NonCopyable的一个私有继承类 */
class SingleCopy : private NonCopyable {};

/** 测试代码 */
int main()
{
    SingleCopy singleCopy1;
    SingleCopy copy(singleCopy1); // 编译器报错：企图复制singleCopy1

    SingleCopy singleCopy2;
    singleCopy2 = singleCopy1; // 编译器报错：企图复制singleCopy1
    return 0;
}</pre></div><p>
            冒号讲解道：“有些对象是不希望被复制的。比如一些代表网络连接、数据库连接的资源对象，它们的复制要么意义不大，要么实现困难。由于C++的编译器为每个类提供了默认的<span class="term">复制构造函数</span>（copy constructor）和<span class="term">赋值运算符</span>（assignment operator），要想阻止对象的复制，通常做法是将这两个函数私有化。引入NonCopyable后，它的任何子类将自动拥有不可复制的特性。这样为开发者节省了代码编写量，还免掉了相应的文档说明，使用者也一望而知其意，可说是一石三鸟。虽然NonCopyable从语法上说不是抽象类，但从本质上看是一种类似mixin功能的抽象类型。”
        </p><p>
            引号考量一番后说道：“单就它的功效而言，的确非常符合mixin的四大特点，只是它的子类用的是私有继承，而不是类继承或接口继承。”
        </p><p>
            “你说得很对。可问题是，我们并没有要求mixin或者trait一定要通过继承的方式来重用啊？事实上，有些mixin甚至可在运行期间产生，还能克服继承的静态缺陷。即使采用继承，一般也不满足‘is-a’关系。你总不能说草莓冰淇淋是一种草莓吧？”冒号淡淡地说，“先前你们总结出抽象类型有两个特征：需要继承和无法实例化，但它们并非本质，关键还是它的目的——为类型服务。提供可被继承的超类型只是一种服务方式，却非唯一的方式；无法实例化只因它不是为对象服务的，禁止实例化不过是语法上的加强，目的是让用户在编译期间就能发现用法错误。其实，即便NonCopyable类的构造函数是公有的，也不会有人去实例化。原因很简单，它的价值只有通过子类才能体现，这是由其抽象的本性所决定的。”
        </p><p>
            逗号有些奇怪：“为什么在Java中就没有类似的对象复制问题呢？”
        </p><p>
            “这是一个非常基础的问题，请容我下次再回答你。”冒号破天荒地没有立即解疑，“以下重点还是放在接口和抽象类上面，我们称之为基本抽象类型，以别于mixin、trait等其他抽象类型。我们先从语法上简单地对比一下这两种类型。”
        </p><p>
            屏幕上显示出一张表格（如表10-1所示）——
        </p><div class="table"><a name="id604285"></a><p class="title"><b>表 10-1. Java/C#的抽象类与接口在语法上的区别</b></p><div class="table-contents"><table summary="Java/C#的抽象类与接口在语法上的区别" border="1"><colgroup><col><col><col></colgroup><thead><tr><th> </th><th>抽象类</th><th>接口</th></tr></thead><tbody><tr><td>提供实现代码</td><td>能</td><td>否</td></tr><tr><td>多重继承</td><td>否</td><td>能</td></tr><tr><td>拥有非public成员</td><td>能</td><td>否</td></tr><tr><td>拥有域成员</td><td>能</td><td>否（Java中的static final域成员除外）</td></tr><tr><td>拥有static成员</td><td>能</td><td>否（Java中的static final域成员除外）</td></tr><tr><td>拥有非abstract方法成员</td><td>能</td><td>否</td></tr><tr><td>方法成员的默认修饰符</td><td>无</td><td>public abstract（Java：可选；C#：不能含有任何修饰符）</td></tr><tr><td>域成员的默认修饰符</td><td>无</td><td>Java：public static final；C#：不允许域成员</td></tr></tbody></table></div></div><br class="table-break"><p>
            冒号简明扼要地总结：“C#的语法与Java的稍有不同，但二者在接口与抽象类的关键区别上还是一致的：接口不能提供实现但能多重继承，抽象类则正相反；接口只能包含<span class="emphasis"><em>公有</em></span>的、<span class="emphasis"><em>非静态</em></span>的、<span class="emphasis"><em>抽象</em></span>的方法成员<a class="link" href="#note9"><sup>[9]</sup></a>，抽象类则无此限制。”
        </p><p>
            问号言明难处：“从语法上区分它们并不难，难的是从设计上区分它们。”
        </p><p>
            逗号实话实说：“按照上节课‘提倡接口继承，慎用实现继承’的方针，应该倾向用接口而非抽象类。但总觉得接口太虚了，没有抽象类实在。”
        </p><p>
            引号反驳：“要说实在，具体类型更实在啊。”
        </p><p>
            叹号坦言：“在编程中经常需要用到标准的或第三方的类库，可查起API来经常是左一个接口右一个接口的，迟迟不见具体类型现身，心里哪个急啊！”
        </p><p>
            冒号打了个比方：“如果到包子铺买包子，作为客户你也许会认为包子是具体类型，但对提供包子的人来说它却是抽象类型。他一定会问你：是要肉包、菜包还是豆沙包？是要蒸包、煎包还是小笼包？他的铺子开得越专业，给你出的选择题越多，众口难调嘛。同样道理， 要建一个高度可重用的类库，一些接口是必不可少的。”
        </p><p>
            句号悟道：“接口的意义就在于：提供者不是擅作主张，而是推迟决定，让客户选择实现方式。”
        </p><p>
            “言之有理！类似地，抽象类的意义就在于：父类推迟决定，让子类选择实现方式。‘推迟’二字道出了抽象类型除创建类型之外的另一功用：<span class="strong"><strong>提供动态节点</strong></span>。如果是具体类型，节点已经固定，没有太多变化的余地<a class="link" href="#note10"><sup>[10]</sup></a>。反过来，要使节点动态化，一般通过多态来实现。由此，抽象类型常常与多态机制形影不离。”冒号稍加引申，“就说前面的验证类吧，用模板方法模式实现的Authenticator类将关键的方法交给子类SimpleAuthenticator或Sha1Authenticator处理，用策略模式实现的Authenticator类将关键的方法交给内嵌接口KeyValueKeeper和Encrypter的实现类处理。后者的两次接口继承比前者的一次实现继承多了一个动态节点，因而更加灵活。这也是为什么一个需要（M×N）个实现类，一个只要（M+N）个的原因。当然，这也不是完全没有代价的。比如要创建一个用SHA-1算法加密的验证类实例，两种方法对比如下——”
        </p><div class="informalexample"><pre class="programlisting">
模板方法模式：new Sha1Authenticator()
策略模式：    new Authenticator(new MemoryKeeper(), new Sha1Encrypter())
</pre></div><p>
            冒号指点着黑板：“显然，后者无论是使用上还是性能上都比前者稍有不如。但权衡利弊，多数时候它仍是更好的选择。” 
        </p><p>
            “包子铺的包子用料种类越多、做法越多，买一个包子越费事。但只要不到饿得发昏的地步，大家还是更喜欢花样更多的包子铺。看来我也不该再抱怨类库的接口过多了。”叹号心下释然。
        </p><p>
            “大家再看看这个电脑主板，开过机箱攒过机的人应该对它并不陌生。”冒号终于亮出了蓄藏已久的道具， “上面密密麻麻地布满了各种元件，那是它的实部，而我们关注的是它的虚部——各种插槽和接口，包括CPU插槽、内存插槽、PCI插槽、AGP插槽、ATA接口、PS/2接口、USB接口以及其他林林总总的扩展插槽等等。这些接口的存在，使得主板与CPU、内存条、外围设备以及扩展卡等不必硬性焊接在一起，大大增强了电脑主机的可定制性。”
        </p><p>
            引号受到启发：“主板与其他硬件就好比一个个的<span class="emphasis"><em>具体类型</em></span>，那些插槽和接口就相当于一个个的<span class="emphasis"><em>接口类型</em></span>。所有的硬件以接口为桥来<span class="emphasis"><em>组装合成</em></span>，以机箱为壳来<span class="emphasis"><em>封装隐藏</em></span>，一个新的<span class="emphasis"><em>具体类型</em></span>——具有完整功能的主机便产生了。”
        </p><p>
            “比喻非常到位！” 冒号很满意，“不过准确地说，与接口类型对应的不是物理接口，而是<span class="strong"><strong>接口规范</strong></span>。如果仅仅是物理接口，只能保证该接口适用于某种特定型号的硬件产品，却不能保证同时适用于其他型号或者其他类型的硬件。以大家熟悉的USB（Universal Serial Bus）接口为例，它能接入各种外部设备，包括鼠标、键盘、打印机、外置硬盘、闪存和形形色色的数码产品。这当然不是偶然的，因为所有厂家在生产这些硬件时均遵循了相同的业界标准——USB协议规范。换言之，任何一个与USB接口兼容的设备，都可看作是实现了此接口的具体类型，而主机对该设备的自动识别能力则可看作一种多态机制。”
        </p><p>
            “这下我更深刻地理解那句话了：接口继承不是为了重用，而是为了被重用。”句号品味道，“比如一个鼠标，可以有串行接口、PS/2接口、USB接口或者无线接口，还可以同时拥有多个不同类型的接口。无论怎样，它本身都是完整的产品，根本不需要重用主机上的其他硬件，它实现某些接口的目的完全是为了能被主机所用。”
        </p><p>
            逗号意识到：“看样子，硬件设计也需要OOP思想呢。”
        </p><p>
            “相比软件设计师，硬件设计师往往能更好地贯彻OOP的理念。”冒号加强了语气，“他们的对象化概念更清晰更自然，因为硬件模块比软件模块更实在更具体；他们更注重设计，因为硬件比软件的修改成本大得多；他们更注重设计重用，因为硬件重新发明轮子的成本普遍很高；他们更注重实现重用，因为无法在举手之间完成‘复制-粘贴’工作；他们更注重接口明确、封装完好，因为把内部的接口或结构暴露在外不仅难看，还容易带来缠绕、磨损、短路等问题；他们采用合成和接口来组装模块，因为硬件没有类似实现继承的机制。”
        </p><p>
            “看起来我们真得向硬件设计师取经了。”叹号有些信服了。
        </p><p>
            冒号旧话重提：“我们曾对OOP有过这样的描述：如果把OOP系统看作民主制社会，每个对象是独立而平等的公民，那么封装使得公民拥有个体身份，继承使得公民拥有家庭身份，多态使得公民拥有社会身份。补充一下，其中的继承主要指类继承，多态主要指接口继承带来的多态。经过这段时间的学习，大家对此有何见解？”
        </p><p>
            问号发表看法：“广义封装让每个类成为独立的模块，从而让每个对象具备了个体身份。狭义封装又进一步地把类的接口与实现分离，从而让每个对象具有显著的外在行为和隐藏的内在特性。继承机制可使一个类成为其他类的子类或父类，从而确立了对象在类型家族中的身份。至于多态嘛，嗯。。。”
        </p><p>
            问号努力想抓住若隐若现的头绪。
        </p><p>
            句号接过话头：“一个公民的社会身份是指他在社会中所处的地位和扮演的角色。比如，一个人在学校里是学生，在公司里是职员，在商店里是顾客，他真正的个体身份往往是被掩盖的。同样地，一个对象在与外界联系时，通常不以其实际类型的身份出现，而是在不同的场合下以不同的抽象类型的身份出现。我想，这大概就是多态带来的社会身份吧。”
        </p><p>
            “这种社会身份的意义何在？”冒号不动声色地问。
        </p><p>
            句号接着回答：“社会身份既是一种资格也是一种义务。比如在列车上有人得了急病，可以通过广播找医生。人们不用事先知道来者的具体个人身份，只要他是医生，就会放心地让他第一时间去救人。”
        </p><p>
            “这个比喻很恰当。”冒号赞道，“不用<span class="emphasis"><em>事先</em></span>知道个人身份，不正说明广播呼叫的对象是一个多态的抽象类型吗？同理，当一个具体类型显式继承了一个接口，它的对象便拥有了个体身份之外社会身份：有资格以该接口的形式与外界打交道，也有义务履行该接口的职责。”
        </p><p>
            “咦，那为什么把社会身份归功于多态而不是继承呢？”问号发出疑问。
        </p><p>
            冒号释疑：“继承自然有功劳，毕竟子类型多态要建立在它的基础上。但如果没有多态机制，要确保一个对象的实际方法而不是其超类型的方法被调用，必须将其还原为具体类型，从而使社会身份变得几乎有名无实。”
        </p><p>
            问号憬然醒悟。
        </p><p>
            冒号继续深入：“对象每多一种社会身份，便多一条与外界交流的渠道。为什么遮遮掩掩地不肯以本来面目示人呢？非是羞于见人，盖因一般的具体类型在公共场合是不为人知的，只有少数核心库里的核心类是例外。即使侥幸被认识，也难被认可，因为那会以代码的复杂度和耦合度为代价。社会身份则不然，它远比一般的个体身份更容易被接受。”
        </p><p>
            逗号举出例证：“这就好比上课得有学生证，上班得有工作证，上火车得有火车票，上飞机得有登机牌。只要不是炙手可热的公众人物，很多场合都是认牌认证不认人的。”
        </p><p>
            “道理人人都懂，可总有不少人以为自己编写的类都是明星大腕，大有‘天下谁人不识我’的豪迈，无牌无证就敢到处乱窜。更有甚者，不用多态就算了，连封装也不要，简直是在裸奔嘛。”冒号揶揄道。
        </p><p>
            全班笑不可仰。
        </p><p>
            冒号恢复肃容：“谈到这里，我们不能不再次提到‘针对接口编程’的基本原则。它有一种建立于数据抽象之上的形式，能让用户只关心抽象数据类型的API接口而无视其具体实现。不过，它至少有两大局限。其一，虽然在接口不变的情况下，实现代码的改变不会影响客户代码，但仍需要重新编译，对于需要头文件的C++来说则需要更多的编译链接时间。其二，虽然相同的接口可以有多种实现方法，但它们不能同时并存，更无法动态切换。于是，另一种建立于多态抽象之上的形式应运而生。它把抽象数据类型隐藏在抽象类型的背后，从而提升了抽象接口。同一个抽象接口允许有多种实现并存，且能动态切换，新增、删除或修改某种实现也不会导致其他代码的修改或重新编译。方才我们从主体类的角度来看，它的对象尽量以社会身份参与社会活动；现在再从客户类的角度看，它会尽量召集有社会身份的对象。两相结合，以社会身份而非个人身份作为公民之间联系的纽带，正是针对接口而非实现来编程的<span class="strong"><strong>社会现实版</strong></span>。”
        </p><p>
            问号有所顾虑：“可是，有不少具体类型并没有实现任何接口，也就没有社会身份。”
        </p><p>
            “排除设计不良的因素，没有抽象超类型的具体类型最常见的有两种可能。一种是与世隔绝，一辈子几乎足不出户，至多在小圈子里活动。典型的有非公有类、内部类、局部类等等。一种是名满天下，他的脸就是一张天然名片，他的个人身份也就是社会身份。典型的有基本数据类型、字符串类型、日期类型等通用数据类型以及特定领域的通用数据类型。可见，个人身份与社会身份并无绝对的界限。同样，家庭身份与社会身份也有交合之处，正如名门望族也可成为社会身份一样。典型的有Java IO库中的InputStream和OutputStream、Reader和Writer，以及UI库中的Component和JComponent等等。”冒号信手拈来，“因此我们谈到的社会身份，不必拘泥于接口，甚至不必限于抽象类型，关键是该类型是否具备了足够的<span class="strong"><strong>通用性和规范性、稳定性和独立性、灵活性和专业性</strong></span>。还是应了那句话：抽象不是目的而是手段。再拿现实社会说事，每种社会身份都代表了个体与社会缔结的一种契约，它有如下的特点：<span class="emphasis"><em>独立而稳定</em></span>——先于个体而存在，且不随个体的变化而变化；<span class="emphasis"><em>公开而权威</em></span>——为人所知、为人所信；<span class="emphasis"><em>规范而开放</em></span>——制定的协议标准明确，且允许个体在遵守协议的前提下百花齐放。毫无疑问，推行契约制将使社会大受其惠。首先，相同身份的个体可相互替换、新型个体可随时加入，而且不会影响整体框架和流程，保证了系统的灵活性和扩展性。其次，整体不因某一个体的变故而受冲击，保证了系统的稳定性和可靠性；最后，个体角色清晰、分工明确，保证了系统的规范性和可读性。”
        </p><p>
            引号非常注重概念：“社会身份所代表的契约对应的正是<span class="term">规范抽象</span>吧。”
        </p><p>
            “每种身份都是规范抽象的结果。” 冒号推而广之，“具体地说，个体身份对应的规范抽象借助封装，以<span class="term">数据抽象</span>（data abstraction）的形式出现；家庭身份对应的规范抽象借助继承，以<span class="term">类型层级</span>（type hierarchy）的形式出现；社会身份对应的规范抽象借助多态，以<span class="term">多态抽象</span>（polymorphic abstraction）的形式出现。至此，我们分别从行为和规范两个角度分别诠释了OOP的三大特征与公民的三大身份之间的关系。这也非常合乎情理：一个合理设计和实现的类，其对象的行为与规范本应保持一致。”
        </p><p>
            句号欲印证自己的想法：“我的理解是，接口是一个携带契约的角色标签，接口继承的作用就是<span class="emphasis"><em>静态地</em></span>为对象贴上该标签，而多态机制的作用就是<span class="emphasis"><em>动态地</em></span>让对象发挥该角色。因此，要赋予对象某个角色，就应该让相应的类去继承相应的接口。”
        </p><p>
            “你的前半部分表述得非常精当，后半部分则稍有瑕疵。”冒号评论道，“接口可用来代表角色，但角色却不一定要通过接口。正如你提到的，接口继承是静态的，而角色却可能是动态的。比如学生毕业后变成职员，职员升迁后变成经理等等。对于静态类型语言来说，这类问题的解决单靠接口继承是不够的，还需要利用合成等手段，或者利用前面提到的其他抽象类型如mixin或trait。”
        </p><p>
            叹号仍有疑惑：“接口的意义已经很清楚了，那抽象类呢？它们的区别真的很大吗？”
        </p><p>
            “我们已经从语法上比较了它们的区别，那些只是表象的东西。如果对语言规则的理解仅仅停留于语法层面，那么它更多体现为<span class="strong"><strong>对实现的束缚</strong></span>。只有提升到语义层面，它才更多体现为<span class="strong"><strong>对设计的保障</strong></span>。”冒号保持一贯高举高打的风格，“从语义上看，抽象类与接口的区别，并不比它与具体类的区别小多少。”
        </p><p>
            叹号错愕不已：“怎么可能？抽象类与接口好歹都是抽象类型啊。”
        </p><p>
            冒号反诘：“为什么不说抽象类与具体类好歹都是类呢？”
        </p><p>
            叹号一时无语。
        </p><p>
            “先看段历史吧。”冒号幽幽地说，“开始C++是没有抽象类型的，直到1989年C++ Release 2.0发布前的最后一刻，Bjarne Stroustrup才力排众议引入抽象类。从C++的前身C with Classes 开始算起，其间已经整整十年了。即便如此，它的意义在当时仍不为大多数人所认识。推出一个看似小小的语法特征竟会如此艰难，恐怕远远超出诸位的想象吧！有人幻想只通过看语法书就能完全领会语言的精髓，又与痴人说梦何异？”
        </p><p>
            冒号的声音渐渐激昂起来。
        </p><p>
            逗号为自己找到了安慰：“难怪当初学到抽象类时，总感到只知其意而不知其用。”
        </p><p>
            冒号紧接着说：“抽象类的出现，让两种不同角色的类在语法上有了明确的界定：具体类<span class="strong"><strong>描述对象</strong></span>，重在实现；抽象类<span class="strong"><strong>描述规范</strong></span>，重在接口。这种分工降低了用户与实现者之间的耦合度，大大减少了代码的维护成本以及编译时间<a class="link" href="#note11"><sup>[11]</sup></a>。由于抽象类不是为了创建对象，它的实例化自然是没有意义的。又由于它是接口规范，在子类没有实现其所有规范之前，是不能实例化的，否则规范岂不成了一纸空文？在没有抽象类的语法之前，要实现类似的功能，唯一的办法是：在本该抽象的方法被调用时强行中止程序。烦琐丑陋不说，还只能在运行期间捕捉错误。在<span class="term">纯虚函数</span>（pure virtual function）——相当于Java和C#中的抽象方法——被引入之后，任何含有抽象方法的类都是抽象类，编译器将保证它不会被实例化。”
        </p><p>
            问号连连点头：“从这个角度来理解抽象类的语法，一切都顺理成章了。不过，抽象类与接口的区别好像还是没有看到。”
        </p><p>
            谈到兴头，冒号出言更如下阪走丸：“从具体类中分离出抽象类是一次质的飞跃，从抽象类中进一步地分离出接口则是另一次飞跃。Java推出接口类型之时同样饱受质疑，最终还是经受了实践的考验，后又为C#所采纳。其实最初C++的抽象类是为了定义一组协议并强令各子类遵守，实质上正是Java和C#中的接口所起的作用。但在协议规范的实现过程中，可能会产生一些不完全实现类。允许这种类的存在固然是一种灵活的举措，但必须认识到它们与纯规范的抽象类已判若云泥。打个比方，如果把对象看作产品，把具体类看作一个制作产品的模具，那么接口就是模具的规格标准，而抽象类是在模具加工过程中产生的半成品。接口与抽象类无法实例化，模具规格与模具半成品也不能直接制作产品；一个具体类可以有多个接口，一个模具也可有多个不同方面的规格；一个具体类至多只能继承一个抽象类，一个模具也至多只能在一种模具半成品的基础上直接加工。”
        </p><p>
            引号细加回味：“如果具体类、抽象类和接口分别对应于模具、模具半成品和模具规格，那后两者的区别的确比前两者的区别还大。可是假如一个抽象类完全没有任何实现呢？抛开多重继承的限制，它与接口又有何区别呢？”
        </p><p>
            冒号辨析其别：“一个抽象类可以没有任何实现，但也随时可以加入实现。接口则不同，永远都不能有实现代码。这正是引入关键字interface的目的，明明白白地表明：此乃规范集合所在，杜绝任何自以为是、画蛇添足的实现。初看似乎不合常理：这不是自缚手脚、自废武功吗？殊不知<span class="strong"><strong>自由源于自制</strong></span>。许多人为了贪恋一点点代码重用，总忍不住把一些实现放在本该只是规范的地方。一来，这模糊了规范与实现的界限，背离了接口与实现相分离的设计初衷。要知道，再完美的实现都有改动的余地，将其捆绑到规范中只会增加不稳定因素；再完美的实现也不应该影响其他的实现，先入为主只会降低灵活性。二来，带有实现的抽象类无法用于合成，必须通过类继承才能起作用，而实现继承的弊端我们已经见识过了。在有些情况下，规范的实现比较复杂，需要渐进实现，保留一些中间状态的抽象类也是合理的，但最初的接口最好保留。总不能因为有了模具半成品，就抛弃模具规格吧？以Java Collections Framework为例，既规范了Collection、Set、List、Map等接口，又为这些接口提供了抽象类和具体类，从而给了用户三种选择：直接利用具体类、扩展抽象类、直接实现接口，方便程度递减而灵活程度递增。”
        </p><p>
            句号进行反思：“我在想，为什么以前对接口总有本能的排斥心理？原因在于：满脑子更多想的是怎么让程序工作，而不是想怎么让程序工作得更好。因此更重视代码实现，比较忽视规范设计。”
        </p><p>
            众人皆有同感。
        </p><p>
            “确实，在缺乏设计观念的人看来，使用接口和脱裤放屁差不多。”冒号轻笑道，“特别需要注意一种常见的说法：接口是为了克服Java或C#中抽象类不能多重继承的缺点。这句话具有相当大的误导性，因为该处的多重继承是指多重实现继承，而接口甚至连单重实现继承都做不到！许多人对接口与抽象类的认识之所以模糊不清，原因是他们习惯于从<span class="emphasis"><em>定义和语法</em></span>中寻找<span class="emphasis"><em>表象的答案</em></span>，不习惯从<span class="emphasis"><em>本源和语义</em></span>上进行<span class="emphasis"><em>本质的分析</em></span>。然而不可否认，毕竟接口与抽象类提供了相似的抽象机制，在实践中往往确难抉择。因此光从语法上对比二者的差别是远远不够的，需要进一步在语义上进行对比（如表10-2所示）——”
        </p><div class="table"><a name="id604782"></a><p class="title"><b>表 10-2. Java/C#的抽象类与接口在语义上的区别</b></p><div class="table-contents"><table summary="Java/C#的抽象类与接口在语义上的区别" border="1"><colgroup><col><col><col><col><col><col><col><col><col></colgroup><thead><tr><th> </th><th>关系</th><th>共性</th><th>特征</th><th>联系</th><th>重用</th><th>实现</th><th>重点</th><th>演变</th></tr></thead><tbody><tr><td><span class="strong"><strong>接口</strong></span></td><td>can-do</td><td>相同功能</td><td>边缘特征</td><td>横向联系</td><td>规范重用</td><td>多种实现</td><td>可置换性</td><td>新增类型</td></tr><tr><td><span class="strong"><strong>抽象类</strong></span></td><td>is-a</td><td>相同种类</td><td>核心特征</td><td>纵向联系</td><td>代码重用</td><td>多级实现</td><td>可扩展性</td><td>新增成员</td></tr></tbody></table></div></div><br class="table-break"><p>
            冒号展开叙述：“先从本性上看：接口是一套功能规范集合，因此相同的接口代表相同的功能，多表示‘can-do’关系，常用后缀为‘-able’的形容词命名，如Comparable、Runnable、Cloneable等等。接口一般表述的是对象的边缘特征<a class="link" href="#note12"><sup>[12]</sup></a>，或者说一个对象在某一方面的特征，因此能在本质不同的类之间建立起横向联系。由于一个对象可拥有多方面的角色特征，故而可有多种接口。与之相对地，抽象类是一类对象的本质属性的抽象，因此相同的抽象基类代表相同的种类，多表示‘is-a’关系，常用名词命名。抽象类一般表述的是对象的核心特征，只能在本质相同的类之间沿着继承树建立起纵向联系。由于一个对象通常只有一个核心，故而只能有一种基类。再从目的上看：接口是为了规范重用，让一个规范有多种实现，看重的是<span class="emphasis"><em>可置换性</em></span>；抽象类主要是为了代码重用<a class="link" href="#note13"><sup>[13]</sup></a>，能逐级分步实现基类的抽象方法，看重的是<span class="emphasis"><em>可扩展性</em></span>。”
        </p><p>
            叹号追问：“演变指的又是什么呢？”
        </p><p>
            冒号答道：“严格说来，演变不属语义范畴，属于语法规则的一个推论。在系统演变过程中，接口与抽象类的表现差异很大。接口由于是被广泛采用的规范，相当于行业标准，一经确立不能轻易改动。一旦被广泛采用，它的任何改动——包括增减接口、修改接口的签名或规范——将波及整个系统，必须慎之又慎。抽象类的演变则没有那么困难，一则它在系统中用得没有接口那么广泛，更多地是家庭身份而非社会身份；二则它可随时新增域成员或有默认实现的方法成员<a class="link" href="#note14"><sup>[14]</sup></a>，所有子类将自动得以扩充。这是抽象类的最大优点之一。不过接口也有抽象类所不具备的优点，虽然自身难以演化，但很容易让其他类型演化为该接口的子类型。例如，JDK5.0之前的StringBuffer、CharBuffer、Writer和PrintStream本是互不相关的，在引进了接口Appendable并让以上类实现该接口后，它们便有了横向联系，均可作为格式化输出类Formatter的输出目标。”
        </p><p>
            问号还留有一个疑点：“现在接口与抽象类之间的差异是越来越清晰了，我只是有一点一直没想通：标记接口究竟有什么用？它一个方法都没有，也就谈不上规范，也无法利用多态机制，继承这类接口又有何意义呢？”
        </p><p>
            逗号随口说：“这就好比有些社会身份是光挂名头不干事的虚衔，不足为奇。”
        </p><p>
            冒号回应道：“先需澄清一点，一个类型的规范不限于单个的方法，类型整体上也有规范，比如主要目的、适用场合、限定条件、类不变量等等。另外，接口的目的是为了产生<span class="emphasis"><em>多态类型</em></span>，不能只看到‘多态’而忽略‘类型’。一个接口哪怕没有一个方法，也是有意义的。首先，接口是一种类型，有严格的语法保障和明确的语义提示，这也是静态类型的优势所在。让一个具体类继承特定接口，既凸显了设计者的用意，也授予用户针对性地处理该类型的权力。比如java.util.EventListener接口为所有的事件监听器提供了统一的根类型。其次，有时需要对某些类型提出特殊要求、提供特殊服务或进行特殊处理，而这些并不能通过公有方法来办到，也没有其他有效的语言支持。标记接口可担此任，成为类型<span class="term">元数据</span>（metadata）的载体。比如给一个类贴上一个java.io.Serializable的标签，它的对象便能被序列化<a class="link" href="#note15"><sup>[15]</sup></a>，具体工作由JVM来完成。用户也可以通过自定义私有的writeObject 、readObject等方法来定制序列化方式。值得指出的是，当标记接口仅仅用于元数据时，更好的办法是采用<span class="term">属性导向式编程</span>（@OP），Java中的annotation、C#中的attribute即作此用。”
        </p><p>
            逗号摸了摸后脑勺：“原来标记接口并非虚有其名，还是在偷偷地干实事呢。”
        </p><p>
            冒号见时候已到，准备落下帷幕：“至此，我们探讨了OOP中最基本的机制——封装、最独特的机制——继承、最重要的机制——多态。在今天的课结束之前，请大家每人用一个关键词来形容自己眼中的OOP，并作简要说明。”
        </p><p>
            引号说：“责任——在契约化的公民社会中，最重要的是对自己、对家庭、对社会的责任感。”
        </p><p>
            问号说：“变化——采用封装以防个人之变，慎用继承以防家庭之变，采用多态以防社会之变。”
        </p><p>
            逗号说：“分合——数据与运算结合，接口与实现分离。”
        </p><p>
            句号说：“抽象——无论是封装、继承还是多态，都是施诸众对象之上的抽象机制。”
        </p><p>
            叹号说：“虚伪——用封装来掩盖内心，用多态来掩盖外表，提倡继承责任却不提倡继承财富！”
        </p><p>
            冒号欣赞道：“不错不错，虽然角度各异，但均深中肯綮。我也大可安心下课了！”
        </p><p>
            众人也乐得打道回府。
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    C#中表示列表和映射的抽象类型（具体类型）分别是IList（List）和IDictionary（Dictionary）。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    此处主要指以继承为基础的抽象类型，如接口与抽象类。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    在C++中，如果一个类不含数据只含抽象的成员函数（即pure virtual function），则该类有时被称为纯抽象类（pure abstract class），与Java和C#中的interface的功用大致相当。
                </p></li><li class="listitem"><p><a name="note4"></a>
                    参考文献【4】和【5】对trait有深入的介绍，并与mixin作了详细的比较。
                </p></li><li class="listitem"><p><a name="note5"></a>
                    该问题的一个解决方式是依赖注射，即把创建被合成对象的职责交给外界。但严格说来这不是合成，而是聚合或关联。它们之间的详细区别请参见§11.2。
                </p></li><li class="listitem"><p><a name="note6"></a>
                    C++可利用CRTP（<span class="strong"><strong>C</strong></span>uriously <span class="strong"><strong>R</strong></span>ecurring <span class="strong"><strong>T</strong></span>emplate <span class="strong"><strong>P</strong></span>attern）的惯用法来实现mixin。
                </p></li><li class="listitem"><p><a name="note7"></a>
                    指C#3.0的扩展方法（extension method）。
                </p></li><li class="listitem"><p><a name="note8"></a>
                    第一个支持OOP的语言是Simula 67（1967年）。
                </p></li><li class="listitem"><p><a name="note9"></a>
                    例外情形：Java的interface可含static final域成员，C#的interface还可含property、event或indexer成员。
                </p></li><li class="listitem"><p><a name="note10"></a>
                    虽然具体类型有可能被继承，但通常并不提倡。
                </p></li><li class="listitem"><p><a name="note11"></a>
                    据参考文献【1】中介绍，一些大型系统在引入抽象类后，编译时间少了一个数量级。
                </p></li><li class="listitem"><p><a name="note12"></a>
                    接口也可能描述对象的核心特征，但一个类至多一个这样的接口。
                </p></li><li class="listitem"><p><a name="note13"></a>
                    由于类继承同时也继承了接口，抽象类也能规范重用，但更侧重代码重用。
                </p></li><li class="listitem"><p><a name="note14"></a>
                    前提是新增的方法成员不与子类型的方法发生冲突。
                </p></li><li class="listitem"><p><a name="note15"></a>
                    严格说来，还要求该类所有非static非transient的域都是可序列化的。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    具体类型是创建对象的模板，抽象类型是创建类型的模块。
                </p></li><li class="listitem"><p>
                    抽象数据类型的核心是数据抽象，而抽象类型的核心是多态抽象。
                </p></li><li class="listitem"><p>
                    抽象类型除了接口和抽象类外，还有mixin、trait等，它们用来克服以下问题——
                </p><p class="simpara"><span class="emphasis"><em>合成的缺陷：</em></span></p><p class="simpara">用法不如继承那么简便优雅；</p><p class="simpara">不能产生子类型；</p><p class="simpara">无法覆盖基础类的方法，也无法访问它的protected成员；</p><p class="simpara">不能以抽象类型为基础类。</p><p class="simpara"><span class="emphasis"><em>具体类型的矛盾与缺陷：</em></span></p><p class="simpara">作为创造对象的单位，功能越多越好；</p><p class="simpara">作为可重用的单位，功能越少越好。</p><p class="simpara">不宜被继承。</p><p class="simpara"><span class="emphasis"><em>接口的矛盾与缺陷：</em></span></p><p class="simpara">客户类希望它提供尽可能多的服务；</p><p class="simpara">实现类希望尽可能少的实现代码。</p><p class="simpara">无法代码重用。</p><p class="simpara"><span class="emphasis"><em>抽象类的缺陷：</em></span></p><p class="simpara">多重类继承或复杂晦涩或未获支持。</p></li><li class="listitem"><p>
                    mixin的特点：抽象性和依赖性；实用性和可重用性；专一性和细粒度性；可选性和边缘性。
                </p></li><li class="listitem"><p>
                    在设计阶段，从具体需求中构建出抽象模型，此时抽象类型尤为关键；在实现阶段，根据抽象模型来完成具体实现，此时具体类型更为重要。
                </p></li><li class="listitem"><p>
                    抽象类型除了能创建类型外，还能提供动态节点，以增加软件的灵活性和可扩展性。
                </p></li><li class="listitem"><p>
                    社会身份代表了个体与社会缔结的一种契约，具有独立、稳定、公开、权威、规范、开放等特点。
                </p></li><li class="listitem"><p>
                    以社会身份作为公民之间联系的纽带，以接口类型作为对象之间联系的纽带。
                </p></li><li class="listitem"><p>
                    系统中广泛用于模块之间通讯的数据类型相当于社会身份，提倡使用接口类型。但也不必拘泥，甚至不必限于抽象类型，关键是要确保该类型的通用性、规范性、稳定性、独立性、灵活性和专业性。
                </p></li><li class="listitem"><p>
                    个体身份对应的规范抽象借助封装，以数据抽象的形式出现；家庭身份对应的规范抽象借助继承，以类型层级的形式出现；社会身份对应的规范抽象借助多态，以多态抽象的形式出现。
                </p></li><li class="listitem"><p>
                    从具体类中分离出抽象类是一次质的飞跃，从抽象类中分离出接口则是另一次飞跃。
                </p></li><li class="listitem"><p>
                    接口与抽象类的语法区别：接口不能提供实现但能多重继承，抽象类则正相反；接口只能包含公有的、非静态的、抽象的方法成员，抽象类则无此限制。
                </p></li><li class="listitem"><p>
                    接口与抽象类的语义区别：接口是一套功能规范集合，相同的接口代表相同的功能，多表示“can-do”关系，一般是对象的边缘特征，在本质不同的类型之间建立横向联系；抽象类是一类对象的本质属性的抽象，相同的抽象基类代表相同的种类，多表示“is-a”关系，一般是对象的核心特征，在本质相同的类型之间建立纵向联系。接口看重规范重用和可置换性；抽象类看重代码重用和可扩展性。
                </p></li><li class="listitem"><p>
                    接口与抽象类的演变：抽象类的演变较为容易；接口自身很难演变，但很容易让其他类型演变为它的子类型。
                </p></li><li class="listitem"><p>
                    标记接口除了能定义类型外，还可作为类型元数据的载体。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Bjarne Stroustrup．The Design and Evolution of C++．Reading, MA：Addison-Wesley，1994．277-281
                </p></li><li class="listitem"><p>
                    Joshua Bloch．Effective Java: Programming Language Guide．Boston, MA：Addison-Wesley，2001．84-88
                </p></li><li class="listitem"><p>
                    Nathanael Schärli，Stéphane Ducasse，Oscar Nierstrasz，Andrew P. Black．Traits: Composable Units of Behaviour．ECOOP，2003，LNCS 2743：248–274
                </p></li><li class="listitem"><p>
                    Stéphane Ducasse，Oscar Nierstrasz，Nathanael Schärli，Roel Wuyts，Andrew P. Black．Traits: A Mechanism for Fine-grained Reuse．ACM Transactions，2006，28(2)：331-388
                </p></li><li class="listitem"><p>
                    Wikipedia．Mixin．<a class="link" href="http://en.wikipedia.org/wiki/Mixin" target="_top">http://en.wikipedia.org/wiki/Mixin</a>
                </p></li></ol></div></div></div>

<!-- below is edited manually -->
<strong><span style="font-family: 宋体">课后思考</span></strong>
<ul style="margin-top: 0cm; list-style-type: none">
    <li>10-01 多态类型在何种程度上解放了静态类型的束缚？</li>
    <li>10-02 请总结参数多态与子类型多态的特点和适用场合。</li>
    <li>10-03 为什么抽象类型如此重要？</li>
    <li>10-04 你认为有必要引入mixin或trait类型吗？</li>
    <li>10-05 区分接口与抽象类的意义何在？</li>
    <li>10-06 你常有往接口中放置代码的冲动吗？</li>
    <li>10-07 如何理解文中“多态使得公民拥有社会身份”这句话？</li>
    <li>10-08 “针对接口编程”与“公民之间以社会身份互相交流”有何相似之处？</li>
    <li>10-09 你是如何理解OOP中抽象、封装、继承和多态的？</li>
    <li>10-10 每当一项新技术出现时，你通常抱什么态度？</li>
    <li>10-11 你会在编程中对某些语法上的限制感到恼火吗？</li>
    <li>10-12  在理解或比较一些编程概念时，你是更习惯从定义和语法的角度，还是更习惯从本源和语义的角度？</li>
    <li>10-13  本课与前课均提到了编程与武术相通之处：攻守兼备，动静得宜，刚柔并济，虚实结合。对此你有何心得体会？</li>
</ul><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F10%2F24%2Fcolon-class-10_2%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A710.2%EF%BC%9A%E6%8A%BD%E8%B1%A1%E7%B1%BB%E5%9E%8B">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/10/24/colon-class-10_2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>冒号课堂§10.1：多态类型</title>
		<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/</link>
		<comments>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/#comments</comments>
		<pubDate>Tue, 20 Oct 2009 09:37:45 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[包含多态]]></category>
		<category><![CDATA[参数多态]]></category>
		<category><![CDATA[多态]]></category>
		<category><![CDATA[子类型多态]]></category>
		<category><![CDATA[模板方法模式]]></category>
		<category><![CDATA[策略模式]]></category>
		<category><![CDATA[继承]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=506</guid>
		<description><![CDATA[<b>多态类型</b>——静中之动（<em>通过实例展示多态类型的三种用法</em>）<br/>
•	继承是多态的基础，多态是继承的目的<br/>
•	多态是动静结合的产物，将静态类型的安全性和动态类型的灵活性融为一体<br/>
•	前者（参数多态）是发散式的，让相同的实现代码应用于不同的场合<br/>
•	后者（包含多态）是收敛式的，让不同的实现代码应用于相同的场合<br/>
•	模板方法模式突出的是稳定坚固的骨架，策略模式突出的是灵活多变的手腕]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center;"><span style="font-family: 宋体;">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体;">第十课 多态机制（1）</span></strong>

<p><strong><span style="font-family: 宋体;">课前导读</span></strong></p>
<p style="text-indent: 18pt;"><span style="font-family: 宋体;">本课通过实例编程和对抽象类型的解读，显示了OOP中多态机制和抽象类型的重要性，有助于培养和加深读者的OOP语感。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-family: 宋体;">本课共分两节——</span></p>
<p style="text-indent: 18pt;"><em>1.</em><em><span style="font-family: 宋体;">多态类型——静中之动</span></em></p>
<p style="text-indent: 18pt;"><em>2.</em><em><span style="font-family: 宋体;">抽象类型——实中之虚</span></em></p>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="多态类型"><div class="titlepage"><div><div><h1 class="title"><a name="id525234"></a>10.1 多态类型——静中之动</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>通过实例展示多态类型的三种用法</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>动静屈伸，唯变所适</p></div><div class="attribution"><span>—<span class="attribution">《王弼•周易略例》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    继承是多态的基础，多态是继承的目的
                </p></li><li class="listitem"><p>
                    多态是动静结合的产物，将静态类型的安全性和动态类型的灵活性融为一体
                </p></li><li class="listitem"><p>
                    前者（参数多态）是发散式的，让相同的实现代码应用于不同的场合
                </p></li><li class="listitem"><p>
                    后者（包含多态）是收敛式的，让不同的实现代码应用于相同的场合
                </p></li><li class="listitem"><p>
                    模板方法模式突出的是稳定坚固的骨架，策略模式突出的是灵活多变的手腕
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>多态与继承有何关系？</p></li><li class="listitem"><p>多态的重要意义何在？</p></li><li class="listitem"><p>多态有哪几种形式？它们各自有什么特点？</p></li><li class="listitem"><p>
                    什么是策略模式？它与模板方法模式有何相同点和不同点？多态在其中起到了什么作用？
                </p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            当冒号迈着不变的步伐出现在教室时，手上有了一点变化：左手仍拎着笔记本包，右手却多了一样东西。大家定睛一看，原来是个电脑主板，不由得暗自纳闷：难道软件课改成了硬件课？
        </p><p>
            冒号照例直入主题：“上节课我们对继承的利弊作了详细的分析，其中最重要的观点是：继承的主要用途不是代码重用，而是代码被重用。这依赖于两个前提，一个是在语义上遵循里氏代换原则，另一个是在语法上支持<span class="term">多态</span>（polymorphism）机制。因此不妨说，对于静态类型语言来说，<span class="strong"><strong>继承是多态的基础，多态是继承的目的</strong></span>。”
        </p><p>
            问号忍不住问：“为什么要强调静态类型呢？”
        </p><p>
            “还记得<span class="term">鸭子类型</span><a class="link" href="#note1"><sup>[1]</sup></a>吗？那就是一种不依赖于继承的多态类型，也是动态类型语言一大优劣参半的特色。”冒号提醒道，“静态类型语言中的多态是动静结合的产物，将静态类型的安全性和动态类型的灵活性融为一体。它一般有两种实现方式：一种利用GP（泛型编程）中的<span class="term">参数多态</span>（parametric polymorphism），一种利用OOP中的<span class="term">包含多态</span>（inclusion polymorphism）或称<span class="term">子类型多态</span>（subtyping polymorphism）。从实现机制上看，二者的不同之处在于何时将一个变量与其实际类型所定义的行为挂钩。前者在编译期，属于<span class="term">早绑定 </span>（early binding）或<span class="term">静态绑定</span>（static binding）<a class="link" href="#note2"><sup>[2]</sup></a>；后者在运行期，属于<span class="term">迟绑定 </span>（late binding）或<span class="term">动态绑定</span>（dynamic binding）。从应用形式上看，前者是<span class="emphasis"><em>发散式</em></span>的，让相同的实现代码应用于不同的场合；后者是<span class="emphasis"><em>收敛式</em></span>的，让不同的实现代码应用于相同的场合。从思维方式上看，前者是泛型式编程风格，看重的是算法的普适性；后者是对象式编程风格，看重的是接口与实现的分离度。尽管二者从范式到语法、语义都大相径庭，但都是为着同一个目的：在保证必要的类型安全的前提下，突破编译期间过于严苛的类型限制。对于既是静态类型语言又是静态语言、既支持OOP又支持GP的C++、Java和C#而言，多态机制是保证代码的灵活性、可维护性和可重用性的<span class="emphasis"><em>终极武器</em></span>。为了说明问题，我们看一个简单而实用的例子：编写一个类，让它能储存用户名和密码，以作今后验证之用。”
        </p><p>
            叹号一愣：“这题是不是太简单了？还有别的要求吗？”
        </p><p>
            冒号摇摇头。
        </p><p>
            引号却认为：“要求太少反而不好做。比如是把数据放在内存、还是文件或者数据库？密码以明文还是密文的形式存储？”
        </p><p>
            句号提出：“无论是数据的存放方式还是密码的加密方式，都不应该硬编码。”
        </p><p>
            “循此思路，我们就来编写一个可重用的抽象类。”冒号投放了一段Java代码——
        </p><div class="informalexample"><pre class="programlisting">
/** 一个可以验证用户名和密码的类  */
abstract class Authenticator
{
    /** 保存用户名和密码  */
    final public void save(String user, String password)
    {
        if (password == null)
            password = "";
        store(user, encrypt(password));
    }

    /** 验证用户名和密码  */
    final public boolean authenticate(String user, String password)
    {
        String storedPassword = retrieve(user);
        if (storedPassword == null) return false; // 无此用户
            
        if (password == null)
            password = "";
        return storedPassword.equals(encrypt(password));
    }

    /** 保存用户名和加密过的密码  */
    protected abstract void store(String user, String encryptedPassword);

    /** 从用户名获取相应的加密过的密码  */
    protected abstract String retrieve(String user);

    /** 给明文单向（one-way）加密，默认不加密  */
    protected String encrypt(String text) { return text; }
}</pre></div><p>
            冒号解说道：“该抽象类有两个public接口，一个用来保存，一个用来验证。它们用final修饰符来禁止子类覆盖，因为真正的扩展点是三个protected方法。其中store和retrieve是抽象的，encrypt有一个平凡实现。以此为基础，再根据实际需要来编写子类，具体实现这三个方法。”
        </p><p>
            幻灯片转到下一页——
        </p><div class="informalexample"><pre class="programlisting">
import java.util.Map;
import java.util.HashMap;

/** 一个简单的验证类，数据放在内存，密码保持明文  */
class SimpleAuthenticator extends Authenticator
{
    private Map&lt;String, String&gt; usrPwd = new HashMap&lt;String, String&gt;();

    @Override protected void store(String user, String encryptedPassword)
    {
        usrPwd.put(user, encryptedPassword);  
    }

    @Override protected String retrieve(String user)
    {
        return usrPwd.get(user);  
    }
}</pre></div><p>
            “我们利用HashMap来储存数据，密码保持明文。这大概是最简单的一种子类了。”冒号仿佛在轻轻地把玩着一件小物什，“为安全起见，最好还是将密码加密。于是我们设计了稍微复杂一点的子类——”
        </p><div class="informalexample"><pre class="programlisting">
import java.security.MessageDigest;

/** 一个安全的验证类，数据放在内存，密码经过SHA-1加密  */
class Sha1Authenticator extends SimpleAuthenticator
{
    private static final String ALGORITHM = "SHA-1"; // SHA-1算法
    private static final String CHARSET = "UTF-8"; // 避免依赖平台

    @Override protected String encrypt(String plainText)
    {
        try
        {
            MessageDigest md = MessageDigest.getInstance(ALGORITHM);
            md.update(plainText.getBytes(CHARSET));
            byte digest[] = md.digest();
            // BASE64编码比十六进制编码节省空间
           //为简便起见用到了非标准的API，因此以下代码有警告 
            return (new sun.misc.BASE64Encoder()).encode(digest); 
        }
        catch (java.security.NoSuchAlgorithmException e)
        {
            throw new InternalError(e.getMessage());  // 不可能发生
        }
        catch (java.io.UnsupportedEncodingException e)
        {
            throw new InternalError(e.getMessage());  // 不可能发生
        }
    }
}</pre></div><p>
            逗号质疑道：“不是具体类不宜被继承的吗？怎么Sha1Authenticator类却继承了具体类SimpleAuthenticator？”
        </p><p>
            冒号略表赞许：“很高兴你没有忘记这个原则。不过考虑到Sha1Authenticator类需要覆盖父类的encrypt方法，这么做也是情有可原的。当然最好选择让该类直接继承抽象类Authenticator，但作为示例代码，我们还是希望它简洁一些，不想让过多的细枝末节掩盖核心主干。下面是测试代码——”
        </p><div class="informalexample"><pre class="programlisting">
public class TestAuthenticator 
{  // 为避免额外依赖，没有采用JUnit等单元测试工具
    public static void main(String[] args)
    {
        test(new SimpleAuthenticator());
        test(new Sha1Authenticator());
    }

    // 测试给定的Authenticator 
    private static void test(Authenticator authenticator) // 子类型多态
    {
        test(authenticator, "user", "password");
        test(authenticator, "user", "newPassword");
        test(authenticator, "admin", "admin");
        test(authenticator, "guest", null);
        test(authenticator, null, "pass");

        authenticator.save("scott", "tiger");
        assert(!authenticator.authenticate("scott", "TIGER")); // 大小写敏感
        assert(!authenticator.authenticate("SCOTT", "tiger")); // 大小写敏感
    }

    private static void test(Authenticator authenticator, String user, String password)
    {
        authenticator.save(user, password);
        assert(authenticator.authenticate(user, password));
    }
}</pre></div><p>
            引号觉得眼熟：“这不是上节课讲的<span class="term">模板方法模式</span>吗？”
        </p><p>
            “正是此公。”冒号确认，“该模式的核心思想是：固定整体框架和流程以保证可重用性，留出一些子类定制点以保证可扩展性。在测试代码的两个test方法中，传入的参数是Authenticator类，但数据存放和密码加密的方式是在运行中才确定的，即先后遵照SimpleAuthenticator类和Sha1Authenticator类的实现。这就是我们所说的子类型多态的效果——让不同的实现代码应用于相同的场合。假设没有多态机制，这种效果就只能靠if/else或switch之类的条件语句才能实现，非常地痛苦。”
        </p><p>
            冒号的眉头皱成了粗体的“川”字。
        </p><p>
            “还有更好的方法吗？”句号察言观色，断定老冒还留有后手。
        </p><p>
            果不其然，冒号的眉毛立刻又舒展开来，中气充沛地应道：“有！诸位请看——”
        </p><div class="informalexample"><pre class="programlisting">
// 键值对的存取接口
interface KeyValueKeeper
{
    public void store(String key, String value);
    public String retrieve(String key);
}

// 加密接口
interface Encrypter
{
    public String encrypt(String plainText);
}

class Authenticator
{
    private KeyValueKeeper keeper;
    private Encrypter encrypter;

    public Authenticator(KeyValueKeeper keeper, Encrypter encrypter)
    {
        this.keeper = keeper;
        this.encrypter = encrypter;
    }

    public void save(String user, String password)
    {
        if (password == null)
            password = "";
        keeper.store(user, encrypter.encrypt(password));
    }

    public boolean authenticate(String user, String password)
    {
        String storedPassword = keeper.retrieve(user);
        if (storedPassword == null) return false;

        if (password == null)
            password = "";
        return storedPassword.equals(encrypter.encrypt(password));
    }
}</pre></div><p>
            冒号加以引导：“如果仔细比较两种设计，就会发现它们很相似。后者只不过把前者对子类开放的接口合成为自己的两个成员。再看接口的实现类——”
        </p><div class="informalexample"><pre class="programlisting">
class MemoryKeeper implements KeyValueKeeper
{
     private Map&lt;String, String&gt; keyValue = new HashMap&lt;String, String&gt;();

    @Override public void store(String key, String value)
    {
        keyValue.put(key, value);  
    }

    @Override public String retrieve(String key)
    {
        return keyValue.get(key);  
    }
}

class PlainEncrypter implements Encrypter
{
    @Override public String encrypt(String plainText)
    {
        return plainText;
    }
}

class Sha1Encrypter implements Encrypter
{
    private static final String ALGORITHM = "SHA-1";
    private static final String CHARSET = "UTF-8"; 

    @Override public String encrypt(String plainText)
    {
        try
        {
            MessageDigest md = MessageDigest.getInstance(ALGORITHM);
            md.update(plainText.getBytes(CHARSET));
            byte digest[] = md.digest();
            return (new sun.misc.BASE64Encoder()).encode(digest); 
        }
        catch (java.security.NoSuchAlgorithmException e)
        {
            throw new InternalError(e.getMessage());
        }
        catch (java.io.UnsupportedEncodingException e)
        {
            throw new InternalError(e.getMessage());
        }
    }
}</pre></div><p>
            逗号比较后得出结论：“MemoryKeeper与SimpleAuthenticator、Sha1Encrypter与Sha1Authenticator除了超类型和方法访问修饰符外，其他毫无二致。”
        </p><p>
            屏幕滚动出另一段代码——
        </p><div class="informalexample"><pre class="programlisting">
public class TestAuthenticator
{
    public static void main(String[] args)
    {
        test(new Authenticator(new MemoryKeeper(), new PlainEncrypter()));
        test(new Authenticator(new MemoryKeeper(), new Sha1Encrypter()));
    }	

    private static void test(Authenticator authenticator) // 隐含子类型多态
    { /* 同上，略 */}
}</pre></div><p>
            “测试代码区别也不大，只是Authenticator的多态性更加隐蔽。”冒号如是说。
        </p><p>
            叹号挑剔说：“后一种创建实例稍显麻烦一些。”
        </p><p>
            “但它是以小弊换大利。”冒号朗声而道，“首先，后者用的是合成与接口继承，比前者的实现继承更值得推荐，理由在上堂课业已阐明。其次，假设共有M种数据存取方式，包括内存、文件、数据库等等；共有N种加密方式，包括明文、SHA-1、SHA-256、MD5等等。按第一种设计，需要（M×N）个实现类；按第二种设计，只要（M+N）个实现类。这还只是两种变化因素，假如需要考虑更多的因素，二者差距将更大。比如增加编码方式：加密后的数据可以选择费空间省时间的十六进制编码、费时间省空间的BASE64编码、省时间省空间却包含非打印字符的原始形式等；比如增加安全强度：引入salt、nonce或IV等<a class="link" href="#note3"><sup>[3]</sup></a>；比如增加密码状态：已生效密码、未生效密码、已过期密码等等。对比下面的UML类图，孰优孰劣更加一目了然。”
        </p><p>
            众人眼前出现了两幅图——
        </p><div class="figure"><a name="id525517"></a><p class="title"><b>图10-1. Authenticator的UML类图（模板方法模式）</b></p><div class="figure-contents"><div class="mediaobject"><img src="http://blog.zhenghui.org/img/colonclass/figure10-1.jpg" alt="Authenticator的UML类图（模板方法模式）"></div></div></div><br class="figure-break"><div class="figure"><a name="id525535"></a><p class="title"><b>图10-2. Authenticator的UML类图（策略模式）</b></p><div class="figure-contents"><div class="mediaobject"><img src="http://blog.zhenghui.org/img/colonclass/figure10-2.jpg" alt="Authenticator的UML类图（策略模式）"></div></div></div><br class="figure-break"><p>
            冒号指着屏幕问：“图二不仅比图一少了三个实现类，而且可重用性也更高。大家说是为什么？”
        </p><p>
            引号应答：“图一中的九个Authenticator的子类只能作为验证类来重用，而图二中六个实现类不仅可以合作完成验证类的功能，还能分别单独提供键值存储和加密字符串的功能。”
        </p><p>
            冒号作出肯定：“这就是职责分离的好处。存储与加密本是两样不相干的工作，必要时可以合作，但平时最好分开管理，符合‘低耦合、高内聚’的原则。”
        </p><p>
            问号注意到图中的注释，遂问：“第二种采用的是策略模式？”
        </p><p>
            冒号颔首：“简单地说，<span class="term">策略模式</span>（strategy pattern或policy pattern）的基本思想是：把一个模块所依赖的某类算法委交其他模块实现。比如Java中的Comparable和Comparator、C#中的IComparer就是比较算法的接口，当一个类的某个方法接收了此种类型的参数，实质上就采用了策略模式。”
        </p><p>
            逗号不以为奇：“这岂非很平常？”
        </p><p>
            “你认为设计模式真的高不可攀吗？”冒号反问道，“包括模板方法模式，你们很可能也在编程实践中采用过，只不过相交不相识罢了。”
        </p><p>
            句号看出：“模板方法模式与策略模式非常神似，都是把一个类的可变部分移交给其他类处理。”
        </p><p>
            “照你这么说，绝大多数设计模式都是神似的，这也是为什么我们不专门谈设计模式的缘故。GoF设计模式是OOP大树上结出的硕果，在你心中培养的OOP成熟之前，匆忙缔结的果实多半是青涩弱小的。”冒号忠告，“我们也不会对设计模式避而不谈，但凡提及都是水到渠成的产物。再说回这两种设计模式，虽然有相通的思想，也能解决相同的问题，在稳定性与灵活性之间都取得了某种平衡，但还是各有侧重的。模板方法模式突出的是稳定坚固的骨架，策略模式突出的是灵活多变的手腕。不妨拿国家政策作比：一个强调对内要稳，老一辈制订了大政方针，下一代必须在坚持原则的前提下进行完善；一个强调对外要活，不能或不便自行开发的技术不妨从国外引进。”
        </p><p>
            叹号一乐：“哈！设计模式上升到了政策模式。”
        </p><p>
            冒号抽丝剥茧：“正如模板方法模式可看作控制反转的特例，策略模式与<span class="term">依赖注射</span>（Dependency Injection）也异曲同工。第二个Authenticator所依赖的两个功能KeyValueKeeper和Encrypter，就是是通过构造方法‘注射’进来的<a class="link" href="#note4"><sup>[4]</sup></a>。当然策略只是一种特殊的依赖，是自内而外的——将算法抽出来外包；依赖注射的机制更复杂、涵盖面更广，是自外而内的——从外部嵌入定制功能。后者被广泛地用于框架应用之中，尤以Spring Framework和Google Guice为代表。”
        </p><p>
            引号听得起劲：“这下热闹了，设计模式、框架与OOP范式全搅和到一块了。”
        </p><p>
            “还有GP范式呢。”冒号顺接话题，“让我们再用C++的模板来实现一下Authenticator类吧。没有继续采用Java，是因为它的泛型仍离不开子类型多态。”
        </p><p>
            说着，他换上了C++代码——
        </p><div class="informalexample"><pre class="programlisting">
#include &lt;string&gt;
#include &lt;map&gt;

using namespace std;

template &lt;typename KeyValueKeeper, typename Encrypter&gt;
class Authenticator
{
private:
    KeyValueKeeper keeper;
    Encrypter encrypter;
public:
    void save(const string&amp; user, const string&amp; password)
    {
        keeper.store(user, encrypter.encrypt(password));
    }

    bool authenticate(const string&amp; user, const string&amp; password) const
    {
        string storedPassword;
        if (!keeper.retrieve(user, storedPassword)) return false;

        return storedPassword == encrypter.encrypt(password);
     }
};

class MemoryKeeper
{
private:
    map&lt;string, string&gt; keyValue;
public:
    void store(const string&amp; key, const string&amp; value)
    {
        keyValue[key] = value;  
    }

    bool retrieve(const string&amp; key, string&amp; value) const
    {
        map&lt;string, string&gt;::const_iterator itr = keyValue.find(key);
        if (itr == keyValue.end()) return false;

        value = itr-&gt;second;  
        return true;
    }
};

class PlainEncrypter
{
public:
    string encrypt(const string&amp; plainText) const { return plainText; }
};

class Sha1Encrypter
{
public:
    string encrypt(const string&amp; plainText) const { /* 省略代码  */ }
};

namespace
{
    template &lt;typename K, typename E&gt;
    void test(Authenticator&lt;K, E&gt; authenticator) // 参数多态
    { /* 省略代码  */ }
}

int main()
{ 
    test(Authenticator&lt;MemoryKeeper, PlainEncrypter&gt;());
    test(Authenticator&lt;MemoryKeeper, Sha1Encrypter&gt;());
    return 0;
}</pre></div><p>
            “以上代码与Java版的策略模式代码很相似，主要的区别是把KeyValueKeeper和Encrypter两个接口换成了模板参数。由于模板是在编译期间实例化的，因此没有动态绑定的运行开销，但缺点是不能动态改变策略<a class="link" href="#note5"><sup>[5]</sup></a>。”冒号分析道，“至此，我们通过一个验证类的三种解法，分别展示了三种形式的多态：基于类继承的多态、基于接口继承的多态和基于模板的多态。它们殊途同归，都能让代码更简洁、更灵活、可重用性更高、更易维护和扩展。”
        </p><p>
            问号想到一个问题：“C语言既没有子类型多态也没有参数多态，又如何保证高质量的C程序呢？”
        </p><p>
            冒号眉梢轻挑：“C语言有指针啊，C++、Java和C#的多态在底层就是用指针实现的。C中的函数指针比Java中的接口更加灵活高效，当然对程序员的要求也更高。”
        </p><p>
            引号蓦地记起：“重载不也是一种多态吗？”
        </p><p>
            “刚才所说的多态都属于<span class="term">通用多态</span>（universal polymorphism）。此外，还有一类<span class="term">特别多态</span>（ad-hoc polymorphism），常见有两种形式。一种是<span class="term">强制多态</span>（coercion polymorphism），即一种类型的变量在作为参数传递时隐式转换成另一种类型，比如一个整型变量可以匹配浮点型变量的函数参数。另一种就是<span class="term">重载多态</span>（overloading polymorphism），它允许不同的函数或方法拥有相同的名字。特别多态浅显易懂，其重要性与通用多态也不可同日而语，故不在我们关注之列。只是要注意一点，正如子类型应遵守超类型的规范，同名的函数或方法也应遵守相同的规范。如果为贪图取名方便而滥用重载，早晚因小失大。”冒号告诫道。
        </p><p>
            逗号突发奇论：“一个多态类型的对象可以在不同的类型之间变来变去，是不是叫‘变态类型’更生动些？”
        </p><p>
            “我看你就属于典型的变态类型。”句号乘机拿他开涮。
        </p><p>
            全班哈哈大笑。
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    参见§5.2。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    虽然C#具体的泛型类型是在运行期间实例化的，但每类泛型对应相同的实现代码，故变量的行为仍是在编译期间决定的。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    salt、nonce和IV都是密码学中的术语，是在加密过程中混入的一次性数据，以增加预计算攻击（如字典攻击）的难度。
                </p></li><li class="listitem"><p><a name="note4"></a>
                    这被称为constructor injection，另外两种常用的注射方法是setter injection和interface injection。
                </p></li><li class="listitem"><p><a name="note5"></a>
                    对用Java实现的Authenticator类（策略模式版）稍作修改，就能让客户动态改变策略。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    在静态类型语言中，继承是多态的基础，多态是继承的目的。
                </p></li><li class="listitem"><p>
                    多态结合了静态类型的安全性和动态类型的灵活性。
                </p></li><li class="listitem"><p>
                    多态可分为通用多态和特别多态两种。
                </p></li><li class="listitem"><p>
                    通用多态主要包括参数多态和包含多态（或子类型多态）。它们都是为了克服静态类型过于严格的语法限制。
                </p></li><li class="listitem"><p>
                    特别多态主要包括强制多态和重载多态。
                </p></li><li class="listitem"><p>
                    参数多态是静态绑定，重在算法的普适性，好让相同的实现代码应用于不同的场合。
                </p></li><li class="listitem"><p>
                    包含多态是动态绑定，重在接口与实现的分离度，好让不同的实现代码应用于相同的场合。
                </p></li><li class="listitem"><p>
                    策略模式授予客户自由选择算法（策略）的权力。
                </p></li><li class="listitem"><p>
                    模板方法模式重在稳定坚固的骨架，策略模式重在灵活多变的手腕。
                </p></li><li class="listitem"><p>
                    合理地运用基于类继承的多态、基于接口继承的多态和基于模板的多态，能增强程序的简洁性、灵活性、可维护性、可重用性和可扩展性。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Erich Gamma，Richard Helm，Ralph Johnson，John Vlissides．Design Patterns: Elements of Reusable Object-Oriented Software．Boston, MA：Addison-Wesley，1994．315-323
                </p></li><li class="listitem"><p>
                    Luca Cardelli，Peter Wegner．On understanding types, data abstraction, and polymorphism．Computing Surveys，1985，17(4)：471-522
                </p></li></ol></div></div></div><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F10%2F20%2Fcolon-class-10_1%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A710.1%EF%BC%9A%E5%A4%9A%E6%80%81%E7%B1%BB%E5%9E%8B">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>《冒号课堂》自序</title>
		<link>http://blog.zhenghui.org/2009/10/16/preface-of-colonclass/</link>
		<comments>http://blog.zhenghui.org/2009/10/16/preface-of-colonclass/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 04:58:31 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[IT]]></category>
		<category><![CDATA[数学]]></category>
		<category><![CDATA[简历]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=493</guid>
		<description><![CDATA[《冒号课堂》一书的序言]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">序</span></h1>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="《冒号课堂》自序"><div class="titlepage"><div><div><div class="author"><h3 class="author">郑晖</h3></div></div></div><hr /></div><div class="toc"><dl><dt><span class="section"><a href="#content"></a></span></dt></dl></div><div class="section"><div class="titlepage"></div><p>
            去年3月的一个下午，过于明媚的春光唤醒了一份久违的情怀，书摊上的一本《青年文摘》便成了合宜的载体。与其说是为了阅读，不如说是为了回忆——对20年前读书心境的回忆。孰料读罢开篇，怀旧之窗随即悄然关掩，一扇求新之门却戛然开启。那是一篇人物介绍，讲述一位籍籍无名的年轻人是如何因撰写博客而声名鹊起的。抚卷思之，网络平台已成大众舞台，人人皆可登台献技，自己何不前去一试？心念甫动，顿感技痒难耐，当晚寝不安席，于辗转反侧之中磨出了一本书的轮廓。
        </p><p>
            尽管钟书先生认为鸡与蛋应为松耦合关系，但一只来历不明的鸡确会招致人们对其产品可靠性的怀疑。故而在介绍《冒号课堂》的创作思路之前，先自我介绍一番。1986年我怀揣着成为数学家的梦想，考入武汉大学数学系。7年的大学生涯在浑浑噩噩中度过，毕业后在广州一所高校教了3年的高等数学。在混沌与迷茫中挣扎了10年，终于不堪蹉跎，1996年赴美攻读数学博士。始料不及的是，在大洋彼岸不仅没能一圆数学之梦，反倒从一个未曾碰过鼠标的电脑排斥者变成了一名IT工作者。“罪魁祸首”正是电脑和Internet，它们潜移默化地改变了人们的生活和思维方式，我亦未能幸免。1998年开始选修计算机课程，两年后拿到硕士学位，并在华尔街的一家软件公司找到了工作。2004年年底，选择回国发展，再度主导了人生的一次急转弯。回到广州后，顺利地进入了一家著名的外企。平淡而安逸的生活似乎注定与我无缘，不久又转去一家小公司作技术总监。如果用一句话来描述自己的职业生涯，那便是：数学是我的初恋情人，计算机是我的终生伴侣。无论成败，都是命运与人生双向选择的结果。
        </p><p>
            本书的创作虽出偶然，却也有其必然性。一方面，市面上的计算机书籍多为拼凑之作，且不少带有应试教育的痕迹。另一方面，论坛上充斥着各种谬言妄论，人们或目空一切，或人云亦云；每当争论一起，常常硝烟弥漫，出言无状者甚众。如此诸般，不忍卒睹。深感激浊扬清之必要，此念一直郁积于心，终至一朝爆发。自知虽无澄清玉宇之力，唯奢念带来一缕清风。
        </p><p>
            《冒号课堂》采用对话体，是为了借不同背景、不同水平、不同性格的人物之口，多层次、多维度、多角度地展现知识的内涵与活性。人物皆以标点符号命名，是为了塑造让人过目不忘的形象：冒号善解释，引号善引用，问号善提问，逗号善缓冲，叹号善感叹，句号善总结。此外，6个标点符号还对应着每小节的6个部分：冒号是正文讲解，引号是文献参考，问号是问题列表，逗号是补充插语，叹号是精华预览，句号是本节总结。与一般纯技术类图书不同，本书非常强调学习方法和学习精神的重要性。在内容组织上也一反常规，以思想为主、以知识为辅，以抽象为主、以具体为辅，以范式为主、以语言为辅。人们常把书籍比作一种食物，其实书籍也是一种药物。一本书应当同时提供两种价值：一种是让人获取正确知识的食用价值，一种是让人抛弃错误观点的药用价值。《冒号课堂》更侧重后者，这多少给读者带来一定的阅读障碍，因为抛弃往往比获取更加困难。此外，全书涉及的知识点较多，覆盖的知识面较广，一些流行的语言或技术反被刻意地淡化。假如读者没有足够的计算机理论和实践基础，难免会感到一些困难和不适。古语有云：“学然后知不足”，认识到不足何尝不是学习的一种收获呢？从另一面说，假如读者发现书中疏谬，还请不吝赐教，本人将不胜感激。坦而言之，随着写作的深入，自得之心日敛，惴惴之心日甚，正应了上面古语的后半句：“教然后知困”。
        </p><p>
            本书的完成首先需要感谢3位母亲：我的母亲、我太太的母亲、我女儿的母亲。没有她们默默无闻的支持和帮助，冒号课堂只能在梦中开班。还要感谢博文视点的周筠老师对本书的大力支持和关怀；白爱萍编辑负责而又耐心，不厌其烦地和我讨论一个个文字和版式的细节；博文的陈宜、杨小勤、陈琼、徐定翔、许莹、胡文佳等编辑也以同样的热情带给我很好的出版体验。我从其他亲友和网友那里也得到了许多热情的鼓励和有益的启示，是他们让虚拟的课堂变得真实和生动。
        </p><p dir="rtl">郑晖</p><p dir="rtl">2009年8月24日于广州</p></div></div><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F10%2F16%2Fpreface-of-colonclass%2F&amp;linkname=%E3%80%8A%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%E3%80%8B%E8%87%AA%E5%BA%8F">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/10/16/preface-of-colonclass/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>冒号课堂§6.4：后台脚本</title>
		<link>http://blog.zhenghui.org/2009/10/10/colon-class-6_4/</link>
		<comments>http://blog.zhenghui.org/2009/10/10/colon-class-6_4/#comments</comments>
		<pubDate>Sat, 10 Oct 2009 01:38:35 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[LAMP]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RoR]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[后台脚本]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=474</guid>
		<description><![CDATA[<b>后台脚本</b>——敏捷开发的利器（<em>简谈Perl、PHP、Python和Ruby</em>）<br/>
•	语言的发展趋势一定是动静结合、刚柔并济<br/>
•	Perl凝练晦涩，Python优雅明晰，Ruby精巧灵动，PHP简明单纯<br/>
•	或许优雅正是来自对细节和规范的重视<br/>
•	（RoR）与Ruby结合之后，便如一只猱身而上灵猫，立刻衬托出Java和.NET大象般的身影]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第六课 语言简评(4)</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="后台脚本"><div class="titlepage"><div><div><h1 class="title"><a name="id600349"></a>6.4 后台脚本——敏捷开发的利器</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>简谈Perl、PHP、Python和Ruby</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>操千曲而后晓声，观千剑而后识器</p></div><div class="attribution"><span>—<span class="attribution">《文心雕龙•知音》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    语言的发展趋势一定是动静结合、刚柔并济
                </p></li><li class="listitem"><p>
                    Perl凝练晦涩，Python优雅明晰，Ruby精巧灵动，PHP简明单纯
                </p></li><li class="listitem"><p>
                    或许优雅正是来自对细节和规范的重视
                </p></li><li class="listitem"><p>
                    （RoR）与Ruby结合之后，便如一只猱身而上灵猫，立刻衬托出Java和.NET大象般的身影
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Perl、Python、Ruby和PHP各自有何特点？</p></li><li class="listitem"><p>为什么动态语言多作为轻量级的解决方案？</p></li><li class="listitem"><p>LAMP为什么受欢迎？</p></li><li class="listitem"><p>Ruby on Rails为什么会流行？</p></li><li class="listitem"><p>编程语言的发展趋势是什么？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            “剩下四种动态语言，我们将之归为<span class="emphasis"><em>后台脚本语言</em></span>。”冒号说着画了张图（如图6-1所示）——
        </p><div class="figure"><a name="id603926"></a><p class="title"><b>图6-1. 常用编程语言的分类</b></p><div class="figure-contents"><div class="mediaobject"><img src="http://blog.zhenghui.org/img/colonclass/figure6-1.jpg" alt="常用编程语言的分类"></div></div></div><br class="figure-break"><p>
            引号听得仔细：“我记得您开始是把这些语言划分为C族静态语言、非C族静态语言和动态语言三类的。”
        </p><p>
            冒号解释：“那是按语法来划分的，偏重理论；现在是按应用来划分，偏重实践。”
        </p><p>
            句号旋即联想到：“这种分法貌似三层架构——前台语言对应表现层；平台语言和后台脚本语言对应业务逻辑层；系统语言对应数据层。”
        </p><p>
            “的确有几分神似，但千万不可混淆。”冒号提醒道，“三层架构（three-layer architecture）是模块设计上的<span class="emphasis"><em>逻辑划分</em></span><a class="link" href="#note1"><sup>[1]</sup></a>；而这里是按语言应用范围进行的<span class="emphasis"><em>物理划分</em></span>——与用户交互的是<span class="term">前台语言</span>，与机器交互的是<span class="term">系统语言</span>，介于其中的为前台提供服务同时又需要底层系统服务的是<span class="term">后台语言</span>。”
        </p><p>
            逗号询问：“后台语言又细分成平台语言与后台脚本语言？”
        </p><p>
            “这是基于程序（program）与脚本（script）、静态与动态而分的。”冒号进行说明，“其实Perl，PHP，Python和Ruby都有自己的<span class="term">虚拟机</span>（virtual machine），从这种意义上说它们也可作为平台语言。但在实际应用中，它们没有Java平台和.NET平台那种整合凝聚力和核心作用，通常作为轻量级的解决方案。”
        </p><p>
            问号想探个究竟：“这是由于它们都是动态语言的缘故吗？”
        </p><p>
            冒号回答：“理论上动态语言同样能承担大型应用，但实践上它们多作为粘合语言或用于中小型应用。用句时髦的话来形容，暂时还是<span class="emphasis"><em>主流的配角</em></span>或<span class="emphasis"><em>非主流的主角</em></span>。毕竟在运行效率、类型安全、可用资源、开发工具、技术支持等方面，它们与Java、C#相比尚有一定差距。另外它们同属‘草根’语言，虽有开源社区的大力支持，在影响力上与后者未可同日而语。”
        </p><p>
            叹号揣测：“说不定在不久的将来，动态语言也会成为主流的主角。”
        </p><p>
            “世易时移，殊难逆料。但有一点可以肯定，语言的发展趋势一定是动静结合、刚柔并济。”冒号断言，“一方面以Java和C#为代表的静态语言中嫁接了动态语言的枝条；另一方面以Java和.NET为代表的平台与动态语言的交壤地带也在逐步扩大。比如JRuby允许Ruby与Java之间互相调用，类似的还有Jython、IronRuby、IronPython等等。此外值得一提的是，动态语言最活跃的舞台当数LAMP，L-A-M-P。”
        </p><p>
            引号接茬：“L是Linux，A是Apache，M是MySQL，P是PHP。这四大组件形成了一个完整的开源网络开发平台。”
        </p><p>
            冒号补充道：“P也可指Perl、Python，甚至Ruby。”
        </p><p>
            逗号调侃：“可惜Ruby的‘R’比‘P’多了一根尾巴。”
        </p><p>
            “有人为了自圆其说，干脆让P表示‘Programming language’，这下所有语言都囊括其中了。老外就喜欢玩这种首字母缩略（acronym）的文字游戏，尤其LAMP正好还有‘灯’的含义，寓意开源世界的一盏明灯，他们一定更得意了。”冒号语带调笑，“前面我们曾提及，网络应用是生长动态语言最肥沃的土壤，而LAMP就是这块土壤上搭建的平台。作为网络平台，LAMP以其开放灵活、开发迅速、部署方便、高可配置、安全可靠、成本低廉等特色而与Java平台和.NET平台鼎足三分，尤其受中小企业的欢迎。LAMP中Linux是操作系统，Apache是Web服务器，MySQL是数据库系统，而我们当下最关心的是‘P族语言’：PHP、Perl、Python还有Ruby。”
        </p><p>
            问号建议：“作为动态语言，它们的共性上节课已经谈了不少，能说说它们的个性吗？”
        </p><p>
            “它们的个性极为鲜明：<span class="strong"><strong>Perl凝练晦涩，Python优雅明晰，Ruby精巧灵动，PHP简明单纯</strong></span>。先看老大哥Perl，它博采众家之长，综合了C语言的结构、sed的正则表达式、AWK的关联数组（associative array）、Lisp的表（list）和Unix Shell的命令，此外还有借鉴了一种语言，你们知道是哪种吗？”冒号忽然卖了个关子。
        </p><p>
            叹号猜想：“应该是某种OOP语言吧。”
        </p><p>
            “Perl中确有不少C++的影子，但它的对象模型在5.0以后才引入，典型的半路出家，远不如前面的特征那么自然。与其说是一种自然而然的发展，不如说是在OOP潮流裹挟下的一种身不由己的迎合。真正深入骨髓的借鉴是自然语言。”冒号给出了答案，“我们提过，Perl的发明者Larry Wall是一名语言学家，他认为程序语言应该与自然语言一样，简洁自然、易读易写、表达多样、不拘一格。Perl还有不少的格言或哲学，使得编程语言一改严谨刻板的面孔，散发出浓郁的人文气息。”
        </p><p>
            逗号幽了一默：“我见过Perl的代码，人文气息没闻出来，但我怀疑有乙醚气息——看一会就觉得晕晕乎乎的。”
        </p><p>
            众人大笑。
        </p><p>
            “有人仅用一行Perl代码就实现了RSA算法，你看了那还不得当场晕倒啊？”冒号打趣道，“Perl的各种魔符好似一把把锋利的剪刀，做起文本裁剪之类的工作来游刃有余。这是它最大的长处，当初Perl就是Wall用来做Unix系统管理的，以后在CGI上的广泛应用也得益于此。这也赋予Perl极强的粘合力，因而有‘internet上的胶带（duct tape）<a class="link" href="#note2"><sup>[2]</sup></a>’的说法。它又号称瑞士军刀，精练而复杂，实用而强大。但Perl过于灵活自由，缺乏规范，影响了程序的可读性、一致性、整洁性和可维护性。不熟悉该语言的固然如读天书，熟悉语言而不熟悉问题的也颇费思量。相比之下Python被认为是Perl有力的挑战者，不仅在于它天然的OO设计和丰富的类库，更重要的是它对程序员友好度大大超过Perl。Python也有一系列的被称为禅（Zen）的哲学，不少与Perl是针锋相对的。比如：Perl认为做一件事可以有多种方法，而Python认为一件事应该最好只有一种方法；Perl追求语言的表现力，Python追求简单优雅；Perl喜欢隐性暗示，Python强调显性明示；Perl强调紧凑，Python强调松散； Perl的语法和语义丰富，Python的语法和语义简单而类库丰富。或许Python最让人不习惯的是它对空白符敏感性。”
        </p><p>
            引号感到惊奇：“对空白符敏感？这个倒真怪异。”
        </p><p>
            冒号见惯不怪：“虽然有点违反习惯，但非常符合Python一贯的规范简洁的风格——一方面从语法上保证了良好的编码风格；另一方面，每个代码块不再需要起始的大括号或begin/end之类的，减少了的代码行数。顺便插一句，另外一种优雅的语言Haskell同样对空白符敏感，或许优雅正是来自对细节和规范的重视吧。此外许多人抱怨Python中的自引用self太多，殊不知这也是它倡导显式表达的一种体现。总的看来，Python主要的问题还是在性能效率上不尽如人意。”
        </p><p>
            叹号好奇地问：“Ruby怎么样？据说它将取代Java。”
        </p><p>
            “不要轻言‘取代’二字。”冒号规诫道，“Java没有取代C++，也不会被Ruby取代，至多只是一种再分配。不过Ruby的确是门很可爱的语言，兼具Perl的表现力和Python的可读性。Ruby背后最具特色的理念是：关注程序员使用语言时的感受超过语言本身的功能。通俗地说，兵器的称手比锋利更重要；文雅地说，应给予程序员更多的人文关怀。就拿<span class="term">代码块</span>（block）和<span class="term">迭代器</span>（iterator）来说，虽然均非Ruby首创，但其语法最为赏心悦目。类似的例子比比皆是。Ruby的元编程能力特别强，也是它高度灵活的一种体现，但并不是所有人都喜欢这种风格。Ruby的主要弱点有两个：一个与Python类似，在性能上还有待提高；另一个是它的线程由<span class="term">用户空间</span>（user space）而不是<span class="term">内核空间</span>（kernel space）来管理<a class="link" href="#note3"><sup>[3]</sup></a>，不能充分利用多核或多CPU。真正让Ruby变得炙手可热的是web应用框架 Ruby on Rails（RoR）的成功，它们还催生了Java平台上的Groovy语言和Groovy on Grails框架。RoR奉行的CoC（Convention over Configuration）和DRY（Don&#8217;t repeat yourself ）原则以及MVC架构看似了无新意，但与Ruby结合之后，便如一只猱身而上灵猫，立刻衬托出Java和.NET大象般的身影。”
        </p><p>
            逗号有些怀疑：“框架竟然捧红了语言，框架真有这么重要吗？”
        </p><p>
            “如果web应用中动态页面较少或业务逻辑不复杂，框架的价值并不大。以前CGI编程就是往Perl之类的代码中嵌入HTML代码，如同Java中的Servlet；PHP则单纯地在HTML代码中插入PHP代码，如同早期的JSP。没有MVC，也不管什么三层架构，更没有ORM。但是——”冒号拖了个转折音，“一旦业务逻辑变得复杂，开发人员增多，手工作坊式编程开始捉襟见肘，引入框架这个流水生产线来提高生产力便是大势所趋。”
        </p><p>
            句号不解：“我想Perl、Python和PHP一定也有不少框架，Java中的框架更是泛滥成灾，何以独独RoR脱颖而出？”
        </p><p>
            冒号作出分析：“正值web2.0和敏捷开发（agile development）的概念流行之际，RoR将AJAX与Ruby组合在一起成为绝佳的回应。以前各种web应用框架是不少，但在RoR之前轻量级<span class="emphasis"><em>套餐式解决方案</em></span>并不多。Perl中的Catalyst、Python中的Pylon还有PHP中的CakePHP等应是效仿之作。因此RoR出现的时机可说是不早不晚，正当其时。此外，Perl和PHP由于过于流行，反而有不少的历史包袱，人们习惯了将表示逻辑和业务逻辑编织在一起。至于Java企业解决方案，框架太多，搭配组合更多，增加了选择的难度。即使采用最常见的轻量级SSH（Struts+Spring+Hibernate）组合，维护起来也比RoR繁杂得多。”
        </p><p>
            叹号愈发担忧：“听这意思，Java还是危险啊！”
        </p><p>
            “言之过早。”冒号不以为然，“首先RoR还有待进一步检验，目前无论是应用广度还是深度上尚无法与Java相提并论；其次Java在性能、安全等方面还是有不少优势，而这些对于大型和关键性的应用来说尤为重要。即使在中小型web应用中，RoR较之PHP还远为不及。”
        </p><p>
            问号接下话题：“PHP为何如此流行？”
        </p><p>
            “因为它简单、专一。”冒号答得很干脆，“与Python和Ruby一开始就定位通用语言不同，PHP是专为网络而生的。同早期的Perl相似，PHP起初主要起文本过滤器的作用，只不过Perl多处理文件流（file stream），而PHP多处理套接字流（socket stream）。PHP的语法简单，且为网络应用度身定造，受到网络开发人员的追捧当在情理之中。它虽很实用很流行，但并不完美。比如：变量名大小写敏感而函数名大小写不敏感；函数命名规则不一致；不支持namespace和unicode<a class="link" href="#note4"><sup>[4]</sup></a>；与Perl一样，它的对象模型不是先天的，直到PHP 5才真正完善；对线程支持不足；相比Perl、Python和Ruby，它的功能稍显单薄等等。”
        </p><p>
            引号突然想起：“我记得您在第一堂课提到PHP还能用于桌面应用。”
        </p><p>
            “不仅PHP，Perl、Python还有Ruby，都能作为前台语言来开发命令行或图形界面的应用。同样地，VB、Delphi和JavaScript也能作为后台语言。现代的程序语言既有自己的专长，又向通用化和全能化发展，以争取更多的生存空间。试想一下，现代的程序员又何尝不是如此呢？”言及于此，冒号收住话题，“语言简评告一段落，还有不少既有趣又有用的语言，在此就不一一评说了。我们看到，每种编程语言都有其独特的惯例用法和哲学理念，它们与编程范式一道形成了语言的编程风格。体悟愈深者编程语感愈强，思维与语言愈交融无碍，渐从必然王国走向自由王国。”
        </p><p>
            逗号满怀憧憬：“那是不是一种人剑合一的境界？”
        </p><p>
            “或许人器合一更准确吧，程序员可不能只会一种兵器哟。”冒号故意抠他的字眼，“现在请大家每人写一句对本节课的感言。”
        </p><p>
            众人沉思片刻，齐齐挥笔而就——
        </p><p>
            <span class="emphasis"><em>叹号——没有最好的语言，只有最合适的语言。</em></span>
        </p><p>
            <span class="emphasis"><em>问号——没有糟糕的语言，只有糟糕的程序员。</em></span>
        </p><p>
            <span class="emphasis"><em>逗号——没有一种语言是万能的，只会一种语言是万万不能的。</em></span>
        </p><p>
            <span class="emphasis"><em>引号——废除对语言的宗教信仰，建立对语言的哲学思维。</em></span> 
        </p><p>
            <span class="emphasis"><em>句号——编程就是在人脑和电脑之间寻找最佳平衡点的过程。</em></span>
        </p><p>
            冒号读罢大悦，顺手一掌拍出五记马屁：“精彩之极！可谓字字珠玑、句句联璧啊。兹决定，给诸位的奖赏是——立时下课！”
        </p><p>
            众人欣然领赏而去。
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    有两种三层架构，一种是three-layer architecture，一种是three-tier architecture。它们经常换用，但其实是有分别的：前者仅仅在逻辑进行划分，而后者在物理上也进行了划分——不同层次的模块运行在不同的主机上。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    不少地方译作“输送带”、“传送带”，因为duct有“输送管”、“导管”之意，于是想当然地认为这表明Perl在internet上起着输送作用。殊不知“duct tape”专指一种万能的粘性极强的胶带，用以比喻Perl的粘合力。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    这类线程被称为绿色线程（green thread），也称伪线程。据称Ruby2.0将支持原生线程（native thread）。
                </p></li><li class="listitem"><p><a name="note4"></a>
                    PHP将在5.3.0支持namespace，将在6.0支持unicode。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    比起Java平台和.NET平台，动态语言轻便灵活、开发效率高，但整合凝聚力还不够，在运行效率、类型安全、可用资源、开发工具、技术支持以及影响力等方面也有一定差距，故通常作为轻量级的解决方案。
                </p></li><li class="listitem"><p>
                    LAMP是由Linux、Apache、MySQL和包括PHP、Perl、Python或Ruby在内的脚本语言组成的网络开发平台，具有开放灵活、开发迅速、部署方便、高可配置、安全可靠、成本低廉等优点。
                </p></li><li class="listitem"><p>
                    Perl精练、复杂、强大、灵活、自由、隐晦、表现力强，但规范性、可读性、一致性、整洁性和可维护性较差。
                </p></li><li class="listitem"><p>
                    Python优雅规范、简洁明晰、易学易用、类库丰富，但效率稍差，有些人不喜欢它对空白符敏感的特性。
                </p></li><li class="listitem"><p>
                    Ruby语法精巧、高度灵活，兼具Perl的表现力和Python的可读性，尤其注重程序员的感受，但其性能和线程模型尚有待改进。
                </p></li><li class="listitem"><p>
                    PHP简单、专一、实用、流行，在但相比其他三种语言，在语法和功能上稍有欠缺。
                </p></li><li class="listitem"><p>
                    RoR是一种轻量级套餐式的web应用解决方案，是由好的设计（MVC架构和CoC、DRY原则）加上好的语言（Ruby）在好的时机（web2.0和敏捷开发风行之际）打造出的好的框架。
                </p></li><li class="listitem"><p>
                    静态语言与动态语言从语言特征到运行环境都在逐渐融合。
                </p></li><li class="listitem"><p>
                    程序员应该与程序语言一样，既要有自己的专长，又要向通用化和全能化发展。
                </p></li><li class="listitem"><p>
                    编程语言惯例用法、哲学理念和编程范式形成了语言的编程风格。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Larry Wall, Tom Christiansen, Jon Orwant．Programming Perl, 3<sup>rd</sup> ed.．Sebastopol, CA：O&#8217;Reilly，2000
                </p></li><li class="listitem"><p>
                    Mark Lutz, David Ascher．Learning Python, 2<sup>nd</sup> ed.．Sebastopol, CA：O&#8217;Reilly，2003
                </p></li><li class="listitem"><p>
                    Michael Fitzgerald．Learning Ruby．Sebastopol, CA：O&#8217;Reilly，2007
                </p></li><li class="listitem"><p>
                    Michele E. Davis, Jon A. Phillips．Learning PHP &amp; MySQL, 2<sup>nd</sup> ed.．Sebastopol, CA：O&#8217;Reilly，2007
                </p></li></ol></div></div></div>

<!-- below is edited manually -->
<strong><span style="font-family: 宋体">课后思考</span></strong>
<ul style="margin-top: 0cm; list-style-type: none">
    <li>06-01 有人认为掌握的语言过多，容易互相混淆，不如精学一门。你认为呢?</li>
    <li>06-02 在实际编程中，你有选择编程语言的权力吗？如果有，选择的原则是什么？</li>
    <li>06-03 在前台编程、后台编程和系统编程中，你主要专注于哪方面？你认为它们之间的主要差别在哪里？</li>
    <li>06-04 你所熟悉的编程语言有哪些惯例用法和哲学理念？</li>
    <li>06-05 试着学习一门新的语言，最好与目前掌握的知识集合互补。</li>
</ul><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F10%2F10%2Fcolon-class-6_4%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A76.4%EF%BC%9A%E5%90%8E%E5%8F%B0%E8%84%9A%E6%9C%AC">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/10/10/colon-class-6_4/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>冒号课堂§6.3：前台语言</title>
		<link>http://blog.zhenghui.org/2009/10/08/colon-class-6_3/</link>
		<comments>http://blog.zhenghui.org/2009/10/08/colon-class-6_3/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 17:00:56 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[VB]]></category>
		<category><![CDATA[前台语言]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=471</guid>
		<description><![CDATA[<b>前台语言</b>——视觉与交互的艺术（<em>简谈VB、Delphi和JavaScript</em>）<br/>
•	Delphi让复杂的事情变得简单，VB让简单的事情变得更简单<br/>
•	它（JavaScript）宛如一只神奇的魔袋，乍看平淡无奇，却总能变出意想不到的宝贝<br/>
•	待友之道，贵在放大其优点而缩小其缺点，对待语言亦当如是<br/>
•	大道相通，难者亦易，易者亦难<br/>
•	得道者化腐朽为神奇，离道者化神奇为腐朽]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第六课 语言简评(3)</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="前台语言"><div class="titlepage"><div><div><h1 class="title"><a name="id603250"></a>6.3 前台语言——视觉与交互的艺术</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>简谈VB、Delphi和JavaScript</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>世人反不难而易之，用是通者亦罕 </p></div><div class="attribution"><span>—<span class="attribution">《欧阳修•诗解统序》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    Delphi让复杂的事情变得简单，VB让简单的事情变得更简单
                </p></li><li class="listitem"><p>
                    它（JavaScript）宛如一只神奇的魔袋，乍看平淡无奇，却总能变出意想不到的宝贝
                </p></li><li class="listitem"><p>
                    待友之道，贵在放大其优点而缩小其缺点，对待语言亦当如是
                </p></li><li class="listitem"><p>
                    大道相通，难者亦易，易者亦难
                </p></li><li class="listitem"><p>
                    得道者化腐朽为神奇，离道者化神奇为腐朽
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Visual Basic和Delphi有何共同点和不同点？</p></li><li class="listitem"><p>相比其他的富客户端技术，JavaScript的前景如何？</p></li><li class="listitem"><p>JavaScript是一门严肃的语言吗？</p></li><li class="listitem"><p>前台编程、后台编程与系统编程，哪个最难？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            稍事休息后，冒号切换了话题：“接下来简单聊聊Visual Basic和Delphi。”
        </p><p>
            叹号略带得色：“Visual Basic最好用了，建个窗体，从工具箱中拖些控件，再定义一下它们的属性和行为，搞定！”
        </p><p>
            冒号点点头：“VB最大的优点就是易学易用、上手快开发快，对非计算机专业人士尤其具有吸引力。”
        </p><p>
            引号咬文嚼字：“言外之意，VB对于专业人士就不那么合适了？”
        </p><p>
            “恐怕也不好这么说。”冒号打了个哈哈，“当然简单易用不是没有代价的，随便拖放一个控件，就生成了一大堆代码，程序员的发挥余地自然受限，代码效率也难以保证。不过VB多用于前台的可视化开发，对运行效率要求相对较低，因此还是很有市场的。另外，VB进化到VB.NET后，从单纯的事件驱动式的编程范式发展为对象式、泛型式和函数式等多种范式，越来越强大、越来越严格也越来越复杂，不再是人们戏称的‘玩具语言’了。”
        </p><p>
            逗号插话：“用Delphi来开发图形界面不也很快吗？”
        </p><p>
            冒号接过话来：“正因为它们擅长可视化快速应用开发（RAD），才常常作为<span class="emphasis"><em>前台语言</em></span>来使用。事实上，它们不单单是语言，也是开发环境。没有IDE，人们照样能写C、C++、Java、Perl等代码，但恐怕很少人会抛开IDE去开发VB或Delphi程序。Delphi又称Object Pascal，前身是<span class="emphasis"><em>教学语言</em></span>Pascal，VB的前身是<span class="emphasis"><em>入门语言</em></span>BASIC（<span class="strong"><strong>B</strong></span>eginner&#8217;s <span class="strong"><strong>A</strong></span>ll-purpose <span class="strong"><strong>S</strong></span>ymbolic <span class="strong"><strong>I</strong></span>nstruction <span class="strong"><strong>C</strong></span>ode），故而均具有易学易用的特点。”
        </p><p>
            问号要求：“能否比较一下二者的优缺点？”
        </p><p>
            冒号回应：“引用Computerworld的评论：‘Delphi让复杂的事情变得简单，VB让简单的事情变得更简单’。Delphi优秀的VCL框架使得它作为前台语言略胜一筹；更高的运行效率使得它同样能胜任后台工作；VB仅限于Windows，而Delphi可移植到Linux下的Kylix；对指针的支持则是便利与复杂的双刃剑。反过来，VB的学习曲线更短；如果专注微软技术，VB更便于扩展开发包括MS Office在内的应用程序，VB.NET更能充分利用.NET平台上的资源；不过VB版本更新较快，在紧跟时代的同时，也给程序员带来恼人的兼容性问题。”
        </p><p>
            句号再次体会到：“正如在Java和C#中作选择一样，平台是语言选择的一个重要因素。”
        </p><p>
            “说得没错。”冒号表示认可，“由于BASIC是微软的起家语言，VB的门槛又低，同时VB.NET也是.NET的一部分，它的前景还是乐观的，有些不利的是微软明显把重心放在C#上。谈到Delphi，不得不提Borland公司。这位曾经的软件巨人开发了无数经典的产品，却因经营不善而日渐没落，不久前将子 公司CodeGear连同包括Delphi在内的产品贱卖给了他人<a class="link" href="#note1"><sup>[1]</sup></a>。”
        </p><p>
            “也许，从当初Delphi的首席架构师Hejlsberg被微软挖走的那一天起，这样的结局就已注定了。”冒号不由得轻叹一声，惋惜之情溢于言表，“这再次说明技术的成功并不意味着商业的成功，同时语言的发展与背后支持的公司也是休戚相关的。Borland和微软是两面最好的镜子。”
        </p><p>
            叹号听出弦外之音：“看来Delphi前景不妙啊。”
        </p><p>
            冒号不置可否：“这也很难说，毕竟Delphi的铁杆拥护者也不少。不过随着基于internet的应用日趋广泛，桌面应用受到网络应用的猛烈冲击，VB和Delphi的市场份额必然都会有所下降。在以网络为中心的企业解决方案中，作为平台语言的Java和C#是两棵比肩而立的大树，在它们周围生长着郁郁葱葱的动态语言的小草。”
        </p><p>
            话题自然而然地转到了动态语言。
        </p><p>
            引号看了看笔记：“按计划，是不是该谈动态语言Perl、PHP、Python、Ruby 和JavaScript了？”
        </p><p>
            冒号说道：“在这些语言中，JavaScript是个异类，虽然也有服务器端的JavaScript（SSJS），但用得最多的还是在客户端。从这种意义上说，它也是一种<span class="emphasis"><em>前台语言</em></span>。”
        </p><p>
            逗号微有疑惑：“您是说将它与方才的VB和Delphi并列？”
        </p><p>
            “有一点不同的是，JavaScript必须与HTML、CSS、XML和XSLT等语言配合才能完成前台工作。”冒号作了补充。
        </p><p>
            问号似乎明白了：“您指的就是流行的AJAX技术吧。”
        </p><p>
            “不完全是。”冒号轻轻摇了摇头，“动态HTML技术（Dynamic HTML，简称DHTML）照样可以胜任前台事务，事实上以前B/S应用<a class="link" href="#note2"><sup>[2]</sup></a>都是靠它来完成浏览器端工作的。DHTML在静态标记语言如HTML、XHTML等的基础上，添加客户端脚本语言如JavaScript、VBScript等，并辅以样式语言如CSS。不少人以为动态HTML与动态网页是同义词，但实际上前者的动态效果来自客户端，后者的动态效果还会来自服务端。至于AJAX（<span class="strong"><strong>A</strong></span>synchronous <span class="strong"><strong>J</strong></span>avaScript <span class="strong"><strong>A</strong></span>nd <span class="strong"><strong>X</strong></span>ML），比DHTML无非多了个XHR （XMLHttpRequest） 的API。XHR最大的功用是能与后台服务器进行<span class="emphasis"><em>异步</em></span>通讯，从而实现页面的局部刷新<a class="link" href="#note3"><sup>[3]</sup></a>，而在此之前类似的效果只能通过IFrame来实现。正是这种异步技术，大大提升了用户体验，使得网页效果开始前所未有地逼近桌面效果。虽然它并非一项新技术——早在2000年的IE5便实现了，但真正流行开来还只是近几年的事。”
        </p><p>
            引号不无担忧：“目前富客户端技术层出不穷，JavaScript的前景如何呢？”
        </p><p>
            冒号给了一颗定心丸：“JavaScript在网页技术中的主流地位在很长时间内恐怕都难以撼动。相比其他的RIA（Rich Internet application）技术，如Adobe的Flex、微软的Silverlight、Sun的JavaFX等，以JavaScript为核心的AJAX技术最大的优势在于：标准、普及、成熟；不需安装插件，只要浏览器支持JavaScript即可；因其<span class="emphasis"><em>文本特征</em></span>而对搜索引擎更加友好。”
        </p><p>
            叹号谈及他的感受：“JavaScript给人的感觉是：看起来很简单，写起来很随意，用起来很头痛。”
        </p><p>
            “原因是多方面的。”冒号谆谆而言，“从JavaScript语言本身来说，其弱类型和动态语言的特征给了程序员更多的自由，也带来更多的混乱；基于原型（prototype-based）的OOP特征远不如基于类(class-based）的OOP那样为人熟知；缺乏丰富的API；不同的浏览器不同的版本之间兼容性差。更主要的是，JavaScript一直被严重低估和误解，自视甚高的程序员往往不屑去编写网页，大多数JavaScript代码由不那么专业的程序员编写。此外IDE与调试工具的缺乏也给开发带来掣肘。这些都加深了人们对JavaScript的简单随意乃至丑陋难用的印象。其实JavaScript作为一门动态语言，集过程式、对象式、函数式、事件驱动式、元编程等于一身，其强大和优雅绝对是超乎想象的。它宛如一只神奇的魔袋，乍看平淡无奇，却总能变出意想不到的宝贝。各位若有机会深入地学习和运用JavaScript，定知我所言非虚。”
        </p><p>
            问号追问：“JavaScript最大的缺点是什么？”
        </p><p>
            “最大的缺点是起了个极无个性的名字。”冒号半开玩笑地说，“为了沾Java的光，Netscape愣将LiveScript改成JavaScript，带来不少混乱。”
        </p><p>
            引号也注意到：“书店、图书馆常常将JavaScript的书与Java的放在一起。”
        </p><p>
            冒号话锋一转：“谈论JavaScript的缺点并没有什么实际意义，因为一时半会还没有同类的替代品。VBScript仅限于微软的IE，在追求跨浏览器和强调标准的今天是不具备竞争力的。ActionScript具有强大的多媒体功能，但必须借助Flash插件，与JavaScript应该是互补共生的关系。另请记住：<span class="strong"><strong>待友之道，贵在放大其优点而缩小其缺点，对待语言亦当如是</strong></span>。这既是一种态度，也是一种境界。”
        </p><p>
            句号发现一个有趣的现象：“初级程序员往往偏爱前台编程，中级以上的偏爱后台编程，有些人则认为只有底层编程的才是真正的高手。”
        </p><p>
            冒号解释道：“前台编程涉及面专，绚丽花哨的界面更容易让初涉编程者产生成就感；后台编程涉及面广，需要深厚的技术积累和缜密的设计思维；底层编程涉及面深，给人神秘莫测之感。<span class="strong"><strong>然大道相通，难者亦易，易者亦难</strong></span>。设计一个用户友好的界面与设计操作系统的一个模块，一边是与人直接打交道，一边是与机器直接打交道，孰难孰易、孰轻孰重，焉能一概而论？”
        </p><p>
            见冒号说得铿锵有力，问号虽不忍置喙，然终难掩疑窦：“用C写操作系统的内核难道不比用VB做一个图形界面难得多吗？”
        </p><p>
            “不可否认，系统编程的门槛确实要高得多，需要程序员具备更多的硬件和操作系统知识和更强的编程能力。”冒号以退为进，“它最大的挑战在于：在相对贫乏的软件资源和相对简陋的开发环境下，能高效、安全地管理包括CPU、内存等在内的系统资源。再说前台编程，虽然入门容易，要想登堂入室却是大为不易。且不说VB、Delphi和JavaScript各具奥妙，连看似简单的HTML和CSS中也蕴含着种种奇思妙想。得道者化腐朽为神奇，离道者化神奇为腐朽，凡事皆然。当然前台最大的挑战还不在代码编写，而在界面设计。软件最终是为人服务的，如果没有良好的用户体验，无论背后的设计如何高明、算法如何精妙，用户也是不会买账的。”
        </p><p>
            叹号充分表示理解：“一个女孩无论多么蕙质兰心、冰雪聪明，如果相貌丑陋、脾气古怪，我也是不会买账的。”
        </p><p>
            逗号故意把脸一沉：“岂有此理，竟然自比为人家的用户！”
        </p><p>
            众人嘎嘎而笑。
        </p><p>
            问号仍有不解：“界面设计不是美工的职责吗？”
        </p><p>
            “美工设计的一般是静态的视觉界面，更重要的是动态的交互界面。相貌再好，脾气不好也不行啊！”冒号顺手拾起了叹号的比方，“虽然近来出现了交互设计师的职位，专门负责UI / UE（<span class="strong"><strong>U</strong></span>ser <span class="strong"><strong>I</strong></span>nterface / <span class="strong"><strong>U</strong></span>ser <span class="strong"><strong>E</strong></span>xperience），但毕竟不是每个公司都有的。即便有，程序员如果缺乏充分的认识，也难以达到设计要求。这可是融美学、心理学、统计学、计算机科学等等于一体的高难度的技术活儿啊！”
        </p><p>
            问号心底泛起的串串疑问的泡泡渐渐开始消散。
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    2008年5月，Borland将CodeGear以两千多万美元卖给Embarcadero Technologies。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    B/S指Browser/Server（即浏览器/服务器）架构，区别于传统的C/S（Client/Server客户机/服务器）架构。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    严格说来，局部页面刷新本身并不需要XHR，但刷新的数据来自XHR。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    Visual Basic和Delphi均擅长可视化快速应用开发，易学易上手，常用于前台的桌面应用。
                </p></li><li class="listitem"><p>
                    Delphi相对VB的优势在于：可视化框架更优秀；运行效率更高；不限于Windows；支持指针。
                </p></li><li class="listitem"><p>
                    VB相对Delphi的优势在于：学习曲线更短；便于扩展开发包括MS Office在内的应用程序；与.NET平台更融合（主要指VB.NET）；有大公司（微软）的支持。
                </p></li><li class="listitem"><p>
                    以JavaScript为核心的DHTML和AJAX技术，相比其他的富客户端技术有其明显的优势：标准、普及、成熟、毋需插件、对搜索引擎友好。
                </p></li><li class="listitem"><p>
                    作为弱类型的动态语言，JavaScript有它的一些问题：基于原型的对象式令人陌生；API相对贫乏；浏览器标准不够统一；IDE和调试工具不够理想；多由不够专业的程序员编写等等。但它本身是一门功能齐全、强大而优美的语言，只要严肃地对待它，它就是一门严肃的语言。
                </p></li><li class="listitem"><p>
                    前台编程涉及面专，更关注界面设计；后台编程涉及面广，更关注业务逻辑；底层编程涉及面深，更关注系统资源。它们只是侧重点有所不同，并无真正的难易之别、高下之分。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Ernesto De Spirito．A comparison between Delphi and Visual Basic．<a class="link" href="http://www.latiumsoftware.com/en/articles/00010.php" target="_top">http://www.latiumsoftware.com/en/articles/00010.php</a>
                </p></li><li class="listitem"><p>
                    David Flanagan．JavaScript: The Definitive Guide, 4<sup>th</sup> ed.．Sebastopol, CA：O&#8217;Reilly，2001
                </p></li></ol></div></div></div><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F10%2F08%2Fcolon-class-6_3%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A76.3%EF%BC%9A%E5%89%8D%E5%8F%B0%E8%AF%AD%E8%A8%80">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/10/08/colon-class-6_3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>冒号课堂§6.2：平台语言</title>
		<link>http://blog.zhenghui.org/2009/10/03/colon-class-6_2/</link>
		<comments>http://blog.zhenghui.org/2009/10/03/colon-class-6_2/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 11:48:57 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[平台语言]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=468</guid>
		<description><![CDATA[<b>平台语言</b>——先搭台后唱戏（<em>简谈Java和C# </em>）<br/>
•	Java的目的是让一种语言在多种平台上运行，而C#（.NET）的目的是让多种语言在一种平台上运行<br/>
•	两个平台语言（Java和C#），一个重在语言，让语言向平台扩散；一个重在平台，让平台来凝聚语言<br/>
•	C++提供了一马平川的大路，也提供了陷阱密布的小道；Java则在大路上铺设水泥，同时封锁了捷径小道；C#同样填平了大路上的坑坑洼洼，但把一些小道上“此路不通”的牌子悄悄换成了“此路危险”]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第六课 语言简评(2)</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>
 
<div lang="zh-CN" class="article" title="平台语言"><div class="titlepage"><div><div><h1 class="title"><a name="id622911"></a>6.2 平台语言——先搭台后唱戏</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>简谈Java和C#</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>大巧在所不为，大智在所不虑</p></div><div class="attribution"><span>—<span class="attribution">《荀子•天论篇》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    Java的目的是让一种语言在多种平台上运行，而C#（.NET）的目的是让多种语言在一种平台上运行
                </p></li><li class="listitem"><p>
                    两个平台语言（Java和C#），一个重在语言，让语言向平台扩散；一个重在平台，让平台来凝聚语言
                </p></li><li class="listitem"><p>
                    C++提供了一马平川的大路，也提供了陷阱密布的小道；Java则在大路上铺设水泥，同时封锁了捷径小道；C#同样填平了大路上的坑坑洼洼，但把一些小道上“此路不通”的牌子悄悄换成了“此路危险”
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>在C++的基础上，Java 与C#作了哪些改进？</p></li><li class="listitem"><p>Java与C#在设计理念上有何不同？</p></li><li class="listitem"><p>Java与C#是如何互相借鉴的？</p></li><li class="listitem"><p>Java与C#为什么擅长企业应用开发？它们能作系统开发语言吗？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            逗号提出：“现在应该到了Java时间吧。”
        </p><p>
            冒号顺水推舟：“下面谈论的重心从刚才的系统语言转到平台语言——Java和C#。”
        </p><p>
            问号听得一头雾水：“平台语言？Java不是平台无关的语言吗？”
        </p><p>
            “平台的意义很广，可以是硬件平台，可以是软件平台，也可以是二者的结合。”冒号解释道，“你说的‘平台’主要指<span class="emphasis"><em>硬件和操作系统平台</em></span>，而我说的‘平台’指的是<span class="emphasis"><em>运行环境平台</em></span>。当然这两种平台是密不可分的，Java与C#之所以能独立于前一种平台，正因为它们自带了后一种平台。具体地说，Java运行于以<span class="term">Java Virtual Machine</span>（JVM） 为核心的Java平台，而C#运行于以<span class="term">Common Language Runtime</span>（CLR）为核心的.NET平台。”
        </p><p>
            句号打了个比方：“这就好比在不同的山路上铺设相同的沥青，车子跑到哪儿都没区别了。”
        </p><p>
            “是这么个理儿。”冒号表示同意，“从传承的角度看，二者皆为基于C++之上的改进，剔除了其中易于出错或不易掌握的语法特征。我们先来看看它们区别于C++的共同之处。首先，二者均编译成<span class="emphasis"><em>与机器无关</em></span>的<span class="term">托管码</span>（managed code）或称<span class="term">字节码</span>（bytecode），运行于<span class="term">虚拟机</span>（virtual machine）之上。其次，禁用或限用指针并支持自动垃圾回收，由此极大地解放了程序员的生产力。起初这种做法并不是没有争议的，但随着机器性能的提高以及软件规模的扩大，对软件的健壮性、安全性和生产率的要求超过了对运行效率的要求，屏蔽指针和自动内存管理逐渐得到认同。尽管如此，指针运算和手动内存管理对于系统软件和在性能、实时性方面要求极高的软件还是必不可少的。因为这个原因，C#还是留了一手：允许标有修饰符unsafe的代码包含指针操作。”
        </p><p>
            引号较起真来：“这是否意味着C#也能作为系统语言呢？”
        </p><p>
            “或许吧。”冒号淡淡地说，“C#的胃口很大，上管天、下管地、中间还要管空气。企业级应用和桌面应用自不必说，底层应用也不放过。早在2003年，微软研究院就开始了用C#开发的名为Singularity的操作系统研究项目，另外还有SharpOS、Cosmos等开源操作系统。虽然它们目前仅用于研究，但不难看出C#的勃勃野心。说起来这也不新鲜，1998年Sun就搞了个针对嵌入式系统的JavaOS，可惜没能成功，后为Java ME所取代。”
        </p><p>
            轮到叹号糊涂了：“刚才还说Java和C#是平台语言，怎么又同C和C++一样当系统语言来用了呢？”
        </p><p>
            冒号释疑：“Java可通过JNI调用C、C++等程序；C#可通过P/Invoke访问系统API，加之保留了指针操作，用于系统编程更加方便。其实一种语言胜任多种领域并不难，难的是在每个领域都独占鳌头。可问题是，有谁不乐见自己支持的语言被广泛应用呢？无论是微软还是Sun，他们都会竭尽所能地将自己的语言扩张到每个角落。程序员作为语言的用户，虽然很多时候并没有选择语言的权力，但心中要有杆秤，可不要轻易被商家的广告迷惑啊。”
        </p><p>
            逗号不无自嘲地说：“秤倒是有一杆，就是不太准啊！”
        </p><p>
            有人“噗哧”笑出声来。
        </p><p>
            “多学习、多实践、多体悟，秤的精度自然会提高。” 冒号鼓励道，“如果自己没有足够的鉴别商品能力，建议从商家的竞争对手那里获取真实的信息。要看Java的优点，不要听Sun的一面之词，可以看看微软的C#模仿了Java的哪些特征，因为模仿是最高的赞扬；要看Java的缺点，可以看看C#摈弃了Java的哪些特征，可以听听微软对Java的批判——虽然可能过激，但一般也不会太离谱。此法同样适用于包括C#在内的其他语言。”
        </p><p>
            句号有所感慨：“这既是程序员之幸——语言之间可以互相取长补短，共同进步；也是程序员之不幸——往往不得不在众多语言中作艰难选择，或者多花精力学更多的语言。”
        </p><p>
            冒号一边点头一边接着说：“下面继续看看Java与C#的共性。借着刚才的话题，我们来看看C#与Java是如何互相学习的。”
        </p><p>
            引号举手插问：“C#到底更接近C++还是Java？”
        </p><p>
            “这是个有趣的问题。不妨这么说：C#看起来更像C++，用起来更像Java。C#借鉴了包括Java、C++、Delphi等在内的语言特征，其中Java的影响最大，但由于微软与Sun在Visual J++上的过节，宁愿强调与C++的关系而淡化与Java的关系<a class="link" href="#note1"><sup><a class="link" href="#note1"><sup>[1]</sup></a></sup></a>。C#的设计者Hejlsberg以前是Delphi和Visual J++的架构师，在一次访谈中首先声明C#不是Java的克隆，但从此话本身和他本人的背景都暗示了与Java千丝万缕的联系。例如，C#采用了大量与Java相同或相似功用却不同拼写的关键字。”冒号投影出一张表格（如表6-1所示）——
        </p><div class="table"><a name="id623019"></a><p class="title"><b>表6-1. Java与C#关键字的比较</b></p><div class="table-contents"><table summary="Java与C#关键字的比较" border="1"><colgroup><col><col><col><col><col><col><col><col><col><col></colgroup><tbody><tr><td><span class="strong"><strong>Java</strong></span></td><td>super</td><td>import</td><td>package</td><td>synchronized</td><td>instanceof</td><td>deprecated</td><td>final</td><td>native</td><td>boolean</td></tr><tr><td><span class="strong"><strong>C#</strong></span></td><td>base</td><td>using</td><td>namespace</td><td>lock</td><td>is</td><td>obsolete</td><td>sealed</td><td>extern</td><td>bool</td></tr></tbody></table></div></div><br class="table-break"><p>
            “这是Java与C#关键字的不完全对照表。中立地看，C#的关键字似乎更简明，但明显避嫌的意义大过改进的意义。关键字只是一个缩影，那么C#究竟从Java那里学到了什么，相比于C++又有什么优势或特点呢？”冒号切换了幻灯片——
        </p><div class="informalexample"><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                        <span class="strong"><strong>更加安全</strong></span>——限用或禁用指针；检查字符串和数组的边界；增加类型安全；禁用未初始化的变量；增加了对资源的安全管理；
                    </p></li><li class="listitem"><p>
                        <span class="strong"><strong>更加简单</strong></span>——自动垃圾回收；废除了头文件和宏（macro）；支持接口（interface）；废除多继承以及非公开继承；摒弃了C++中一些生僻、难用的语法；
                    </p></li><li class="listitem"><p>
                        <span class="strong"><strong>更加中性</strong></span>——编译成机器无关代码；运行于统一平台；
                    </p></li><li class="listitem"><p>
                        <span class="strong"><strong>更加OO</strong></span>——不支持全局变量和自由函数；所有的类都可上溯到Object类；对象一般通过new分配在堆（heap）上；
                    </p></li><li class="listitem"><p>
                        <span class="strong"><strong>更加丰富</strong></span>——支持反射（reflection）；支持并发编程；提供图形界面、网络编程、数据库、XML等API；
                    </p></li><li class="listitem"><p>
                        <span class="strong"><strong>更加标准</strong></span>——更好的Unicode支持；支持注释性文档；类或方法可以被废弃（deprecated）；
                    </p></li></ul></div></div><p>
            问号就势而问：“Java向C#又借鉴了什么呢？”
        </p><p>
            冒号答道：“在Java1.5的增强特征中，有不少C#的影子。如增强版的for循环；可变长参数（varargs）；自动装箱（autoboxing）；类型安全的枚举（typesafe enum）等等。此外，支持元数据的的注释（annotation）与C#的特性（attribute）大同小异，C#从Delphi中引入的属性（property）也出现在Java 7的提案中。”
        </p><p>
            逗号双手一摊：“这么多相同之处，不如合并算了。”
        </p><p>
            “很傻很天真的想法。等它们合并了，估计世界也大同了。”冒号笑言，“它们之间的差别也不容忽视。C#重新捡起了C++中被Java抛弃的一些特征，可谓是对C++的<span class="strong"><strong>否定之否定</strong></span>——除了支持<span class="term">引用类型</span>（reference type）外，还支持<span class="term">值类型</span>（value type）<a class="link" href="#note2"><sup>[2]</sup></a>；除了<span class="term">按值传递</span>（pass-by-value）外，还可<span class="term">按引用传递</span>（pass-by-reference）；支持<span class="term">操作符重载</span>（operator overloading）；在一定条件下保留指针和指针运算；所有的方法默认是非虚的（non-virtual）；访问权限默认是私有的（private）；将关键字‘extends’和‘implements’统一为‘：’；支持<span class="term">预处理指令</span>（preprocessor directive）；C#4.0还将引入<span class="term">可选参数</span>（optional parameter）等等。公允地说，这些大都为明智之举。”
        </p><p>
            引号追问：“C#有什么独到之处吗？”
        </p><p>
            “C#并非一味地效仿其他语言，也有创新之举。曾在Visual J++中加入的<span class="term">委托</span>（delegate）和相关的<span class="term">事件</span>（event），如今可以堂而皇之地用在C#上，再不用担心被Sun告了。”冒号语带调侃，“C#还是第一个支持<span class="term">组件导向</span>（Component-Oriented）的C族语言。除此之外，C#支持<span class="term">索引器</span>（indexer）、<span class="term">版本控制</span>（versioning）、XML注释、特色指令如#region、特色关键字如checked、yield等等，还引入了查询句法（query syntax）、匿名类型（anonymous type）、扩展方法（extension method）等新特征。还有一点不得不提，C#对函数式编程的支持力度逐渐加大：1.0的delegate可作为头等函数（first-class function），2.0的匿名delegate可作为闭包，3.0又引入了Lambda表达式，几乎可号称函数式语言了。及至C#4.0，进一步向动态语言靠拢，将引入关键字dynamic以支持动态类型和动态操作。”
        </p><p>
            叹号眉头微蹙：“听起来C# 比Java复杂多了，好像大杂烩。”
        </p><p>
            “当初Java对C++的改革的一个重要原则是：让语言变得简单而有亲和力，降低程序员门槛，提高软件生产效率。但如今Java已经不那么简单了，C#则更复杂，在某些方面较之C++也不遑多让。” 冒号语调转强，“以前人们试图在语言的<span class="emphasis"><em>威力</em></span>（power）和<span class="emphasis"><em>生产率</em></span>（productivity）中寻求最佳平衡点，现在似乎更想鱼与熊掌兼得。”
        </p><p>
            问号再次提问：“Java与C# 最大的区别是什么？”
        </p><p>
            “虽然同为平台语言，二者的设计理念还是有所不同的。<span class="strong"><strong>Java的目的是让一种语言在多种平台上运行<a class="link" href="#note3"><sup>[3]</sup></a>，而C#（.NET）的目的是让多种语言在一种平台上运行</strong></span><a class="link" href="#note4"><sup>[4]</sup></a>。”冒号钟爱这种具有对称美的对比，“虽然理论上以C#为核心的.NET平台可以用在任何操作系统上，但千万不要指望微软会心甘情愿地提供Windows之外的实现<a class="link" href="#note5"><sup>[5]</sup></a>，原因不言自明。而Sun的Solaris无法与Windows抗衡，最大的王牌就是Java语言，当然会致力于跨平台和面向Internet的应用，对桌面应用的投入相对较少。另外，Sun不像微软那样控制着包括C#、VB、C++/CLI、J#、JScript.NET等在内的多种语言，对跨语言的热情度相应也低得多。尽管Java能与Groovy、JRuby、JPython等以JVM为基础相互调用，不过与其说这是Java的初衷，不如说是自然发展的结果。因此两个<span class="strong"><strong>平台语言</strong></span>，一个<span class="strong"><strong>重在语言</strong></span>，让语言向平台扩散；一个<span class="strong"><strong>重在平台</strong></span>，让平台来凝聚语言。在此并不想对两公司的商业策略评头论足，而是认为了解这种背景会对理解语言特征及其发展趋势有所裨益。编程语言绝非象牙塔中之物，实乃技术和商业合力推动的结果。”
        </p><p>
            逗号拖着怪腔：“原来如彼！”
        </p><p>
            众人大笑。
        </p><p>
            句号深思后问道：“可不可以这么理解：如果开发仅限于Windows平台的应用，C#是更好的选择，它一方面与Windows系统存在天然的纽带，另一方面可有效地利用.NET的包括ASP.NET、VB.NET、ADO.NET、Windows Forms、WPF、WCF、WF等在内的各种软件资源；如果开发不限于Windows的企业应用，则选择Java更合适？”
        </p><p>
            冒号微微颔首：“有一定道理，平台的确是语言选择的一个考虑因素。不过说起可利用的软件资源，Java毫不逊色。除了形形色色的开源框架和工具外，与动态语言如Groovy、Scala、Ruby、Python等也能严丝合缝。作为平台语言，Java和C#均有极为丰富的资源和极强的整合能力，背后又有大公司不遗余力的支持和推广，理所当然地成为大型企业应用的主流选择。”冒号匆匆作结，“关于Java与C#的比较暂时谈到这里<a class="link" href="#note6"><sup>[6]</sup></a>，由于时间关系，我们不可能面面俱到，难免挂一漏万。许多概念术语只是点到为止，具体细节留待以后展开，暂且按下不表。总而言之，每种语言都为解决问题提供了一定的途经，C++、Java和C#的不同之处在于：C++提供了一马平川的大路，也提供了陷阱密布的小道；Java则在大路上铺设水泥，同时封锁了捷径小道；C#同样填平了大路上的坑坑洼洼，但把一些小道上‘此路不通’的牌子悄悄换成了‘此路危险’。” 
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    在C#的语言规范（language specification）中，多处提到C和C++，但对Java只字不提。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    C#保留了C++中的struct关键字作为值类型，以区别于class所代表的引用类型。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    此处的平台主要指操作系统。另外，近来Java平台也大有凝聚其他语言的倾向，尤以Groovy、Ruby、Python、Scala等动态语言为代表。
                </p></li><li class="listitem"><p><a name="note4"></a>
                    严格来说应当是“.NET 的目的是让多种语言在一种平台上运行”。文中说法是因为C#是本节的谈论主体，并且作为.NET的核心语言，其设计也遵循该理念。
                </p></li><li class="listitem"><p><a name="note5"></a>
                    Novell公司开发的Mono项目是.NET平台的一种开源实现，可以在Windows以外的操作系统如Unix、Linux、Mac OS X等上运行。
                </p></li><li class="listitem"><p><a name="note6"></a>
                    参考文献【3】和【4】对Java和C#进行了非常详尽的比较。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    相比C++，Java与C#更加安全（限用指针、数组边界检查、类型安全、资源管理等）、简单（自动垃圾回收、废除多继承和头文件等）、中性（编译成机器无关的字节码，运行于虚拟机）、OO（无全局变量和函数等）、丰富（支持反射和并发编程、更完备的API等）、标准（注释性文档、更好的Unicode支持等）。
                </p></li><li class="listitem"><p>
                    Java的目的是让一种语言在多种平台上运行，而C# （.NET）的目的是让多种语言在一种平台上运行。Java重在语言，让语言向平台扩散；C#重在平台，让平台来凝聚语言。
                </p></li><li class="listitem"><p>
                    虽然系统开发并非Java与C#的禁区，它们更多地还是用于企业级应用开发。丰富的资源、强大的整合能力和巨头公司的鼎力支持是它们得天独厚的优势。
                </p></li><li class="listitem"><p>
                    编程语言的发展是技术和商业合力推动的结果。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Jesse Liberty．Programming C#, 2<sup>nd</sup> ed.．Sebastopol, CA：O&#8217;Reilly，2002
                </p></li><li class="listitem"><p>
                    Ecma International．Standard ECMA-334(C# Language Specification, 4<sup>th</sup> ed.)．<a class="link" href="http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf" target="_top">http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf</a>
                </p></li><li class="listitem"><p>
                    Dare Obasanjo．A COMPARISON OF MICROSOFT&#8217;S C# PROGRAMMING LANGUAGE TO SUN MICROSYSTEMS&#8217; JAVA PROGRAMMING LANGUAGE．<a class="link" href="http://www.25hoursaday.com/CsharpVsJava.html" target="_top">http://www.25hoursaday.com/CsharpVsJava.html</a>
                </p></li><li class="listitem"><p>
                    Wikipedia．Comparison of Java and C Sharp．<a class="link" href="http://en.wikipedia.org/wiki/Comparison_of_Java_and_C_Sharp" target="_top">http://en.wikipedia.org/wiki/Comparison_of_Java_and_C_Sharp</a>
                </p></li><li class="listitem"><p>
                    Mads Torgersen．New features in C# 4.0．<a class="link" href="http://code.msdn.microsoft.com/csharpfuture/Release/ProjectReleases.aspx?ReleaseId=1686" target="_top">http://code.msdn.microsoft.com/csharpfuture/Release/ProjectReleases.aspx?ReleaseId=1686</a>
                </p></li></ol></div></div></div><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F10%2F03%2Fcolon-class-6_2%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A76.2%EF%BC%9A%E5%B9%B3%E5%8F%B0%E8%AF%AD%E8%A8%80">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/10/03/colon-class-6_2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>冒号课堂§6.1：系统语言</title>
		<link>http://blog.zhenghui.org/2009/09/29/colon-class-6_1/</link>
		<comments>http://blog.zhenghui.org/2009/09/29/colon-class-6_1/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 04:18:29 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[C族语言]]></category>
		<category><![CDATA[C语言]]></category>
		<category><![CDATA[D语言]]></category>
		<category><![CDATA[系统语言]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=466</guid>
		<description><![CDATA[<b>系统语言</b>——权力的双刃剑（<em>简谈C、C++和D</em>）<br/>
•	通禅悟道者拈花不语，坐井观天者蛙鸣鼓噪<br/>
•	Java程序员大多被惯坏了，环保意识要淡薄得多<br/>
•	（指针）用得好可以是削铁如泥的神兵利器，用得不好则可能是自我毁灭的罪恶渊薮<br/>
•	OOP又不是金子，含量越高越好。试图把一切都装进OOP的箱子里的想法无异于削足适履<br/>
•	它们（系统语言）的理念是：优化机器的时间而不是人的时间，优化机器的记忆而不是人的记忆；假设编译器是愚蠢的而程序员是聪明的，因此赋予程序员更多的权利、义务与责任<br/>
•	C++是匹无辔无鞍的野马，看似桀骜不驯，若能顺性而御，必能足踏飞燕，行千里而不劳]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center;"><span style="font-family: 宋体;">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体;">第六课 语言简评（1）</span></strong>

<p><strong><span style="font-family: 宋体;">课前导读</span></strong></p>
<p style="text-indent: 18pt;"><span style="font-family: 宋体;">本课对一些主流语言进行了简单的比较和评价。一家之言，权作助兴。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-family: 宋体;">本课共分四节——</span></p>
<p style="text-indent: 18pt;"><em>1.</em><em><span style="font-family: 宋体;">系统语言——权力的双刃剑</span></em></p>
<p style="text-indent: 18pt;"><em>2.</em><em><span style="font-family: 宋体;">平台语言——先搭台后唱戏</span></em></p>
<p style="margin-left: 18pt;"><em>3.</em><em><span style="font-family: 宋体;">前台语言——视觉与交互的艺术</span></em></p>
<p style="margin-left: 18pt;"><em>4.</em><em><span style="font-family: 宋体;">后台脚本——敏捷开发的利器</span></em></p>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="系统语言"><div class="titlepage"><div><div><h1 class="title"><a name="id656771"></a>6.1 系统语言——权力的双刃剑</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>简谈C、C++和D</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>居高者形逸而神劳，处下者形劳而神逸</p></div><div class="attribution"><span>—<span class="attribution">《洪应明•菜根谭》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    通禅悟道者拈花不语，坐井观天者蛙鸣鼓噪
                </p></li><li class="listitem"><p>
                    Java程序员大多被惯坏了，环保意识要淡薄得多
                </p></li><li class="listitem"><p>
                    （指针）用得好可以是削铁如泥的神兵利器，用得不好则可能是自我毁灭的罪恶渊薮
                </p></li><li class="listitem"><p>
                    OOP又不是金子，含量越高越好。试图把一切都装进OOP的箱子里的想法无异于削足适履
                </p></li><li class="listitem"><p>
                    它们（系统语言）的理念是：优化机器的时间而不是人的时间，优化机器的记忆而不是人的记忆；假设编译器是愚蠢的而程序员是聪明的，因此赋予程序员更多的权利、义务与责任
                </p></li><li class="listitem"><p>
                    C++是匹无辔无鞍的野马，看似桀骜不驯，若能顺性而御，必能足踏飞燕，行千里而不劳
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>为什么C++不支持自动垃圾回收？</p></li><li class="listitem"><p>在C++中如何解决内存释放问题？</p></li><li class="listitem"><p>系统语言有哪些特点？</p></li><li class="listitem"><p>在不引入OOP的前提下，C语言可以借鉴C++的哪些特征？</p></li><li class="listitem"><p>D语言比C++有哪些改进？</p></li><li class="listitem"><p>在电脑性能日益提升的今天，还有必要在乎程序的性能和效率吗？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            教室里，学员们正热火朝天地讨论着流行的编程语言。冒号推门而入，仿佛沸水锅里被浇了一瓢冷水，立刻平静下来。
        </p><p>
            冒号笑吟吟地看着大家：“怎么不讨论了？”
        </p><p>
            众人齐道：“该您了！”
        </p><p>
            “首先需要声明的是，本课评论编程语言，乃是应众位之邀，实非本意。”冒号变得严肃起来，“因为这种评论，不可避免地会带上个人色彩，容易产生误导。有道是，<span class="strong"><strong>通禅悟道者拈花不语，坐井观天者蛙鸣鼓噪</strong></span>。”
        </p><p>
            众人迅速自动对号：合着我们就是一群蛤蟆。
        </p><p>
            “这样一来，我的处境就很尴尬了。”冒号自嘲着。
        </p><p>
            有人在幸灾乐祸地偷笑。
        </p><p>
            “也罢，即使作蛙鸣，至少也要先跳出井来。”冒号毅然决然地加入了蛤蟆的行列，“要谈，就旗帜鲜明地谈，该赞叹的就赞叹，该鄙视的就鄙视。说些你好我好大家好之类不痛不痒的话，倒不如不说。”
        </p><p>
            叹号一拍大腿：“好，这样才够痛快！”
        </p><p>
            问号忍不住问：“您究竟打算比较哪些主流语言呢？”
        </p><p>
            冒号回答：“就谈谈第一堂课提到的最流行的十二种语言吧。按语法特征可将它们分为三类：C族静态语言五种——C、C++、Java、C#和D；非C族静态语言两种——VB和Delphi；动态语言五种——Perl、PHP、Python、Ruby 和JavaScript 。”
        </p><p>
            叹号表示怀疑：“这么多种语言怎么比较得过来？”
        </p><p>
            冒号解释：“我们主要比较第一类的C族语言，这些也是今后学习的重点，其他的只是泛泛而谈。”
        </p><p>
            引号猜测：“因为他们更重要？”
        </p><p>
            “可以这么说。”冒号直截了当，“毋庸讳言，在当今的主流语言中，C族语言应用范围之广、使用人数之多、影响力之巨都是其他类语言所无法比拟的。它们之间的关系从名字上就能看出：C语言的前身是B语言；其后是C++；Java曾被称为C++++&#8211;，意思是在C++上增点东西再减点东西；C#中#就是四个叠起的加号<a class="link" href="#note1"><sup>[1]</sup></a>；最后D语言干脆在字母上进行升级。”
        </p><p>
            句号推断：“B语言、C语言、D语言，下一个该D++、D#或E语言了。”
        </p><p>
            谁知冒号却说：“E语言已经有了，与Java的语法很像。甚至F语言也有了，但不是C族语言，而是Fortran族的。这不，微软还在.NET平台上推出了F#语言，不过这里的F指的是‘Functional’，即函数式。”
        </p><p>
            逗号向往着：“不如直接搞个终极的Z语言，成为全世界程序员的唯一指定语言，多省事！”
        </p><p>
            “这难度不亚于全人类共用一种语言。”冒号笑道，“愿望是美好的，我们还得面对现实。不扯远了，你们先谈谈一下这些C族语言各自的特点吧。”
        </p><p>
            众人心想：老冒怎么跟国足一个毛病，老喜欢回传，就是不直接射门，真是急煞人也！
        </p><p>
            问号拣了个软柿子：“C语言是C族老大，又是唯一的纯过程式语言，当然与众不同啦。”
        </p><p>
            引号一板一眼：“C++在过程式的基础上又引入对象式和泛型式，同时保持了C的高效性和底层开发能力。”
        </p><p>
            逗号接道：“Java既继承了C++的优点，又克服了C++的复杂性，虽然底层开发能力有所减弱，但具备平台无关性。”
        </p><p>
            句号不紧不慢：“C#兼具C++与Java各自的优点，但效率上不如C++，跨平台方面不如Java。”
        </p><p>
            叹号后悔嘴慢：“剩下一个最陌生的D语言，在第一堂课之前还真没听说过，怎么挤上主流语言位置的？我想。。。呃，它总该比C++要高级吧。”
        </p><p>
            冒号评价：“各位谈得虽然简单了些，也算八九不离十吧。下面我稍微展开些来讲。”
        </p><p>
            此时众人有一个共同的愿望，希望老冒这次能痛快地单刀赴会、直捣黄龙。
        </p><p>
            冒号似乎看出大家的心思，开始口若悬河：“关于C语言，前面多次提到。这是一把历久弥新的宝剑，一旦出鞘，依旧寒光逼人，锋利无俦。有了它，便如战将有了佩剑，平添一分独闯敌营的胆气。尽管以现代的眼光来看，它存在不少缺点，但即使抛开C语言辉煌的历史不谈，单就其以如此高龄在诸多后辈冲击之下仍屹立不倒而论，让人无法对其多加苛求。”
        </p><p>
            逗号提出异议：“但语言不是让人崇拜的，而是让人运用的。一门语言无论过去如何荣光，如果不适应现代发展趋势，还是可能被淘汰。”
        </p><p>
            “说得非常好！”冒号竟然鼓起掌来，“迄今为止本课堂对于具体知识的讲授不算太多，但一直提倡独立思考，不要盲从权威。如果你们能做到这一点，本班的目标也就实现了一半。回头再说说C语言，它源自Unix操作系统的开发，以其良好的抽象性和可移植性取代了汇编语言作为系统开发语言。因其简洁实用、灵活高效，很快从系统领域发展到其他领域而成为通用语言。随着新兴语言的崛起以及硬件性能的大幅提高，C语言的缺点也日益显著：过于宽松的类型检查、容易出错的内存管理、相对贫乏的语言特征等等。虽然自身还在发展，它的市场份额日益减少乃是不争的事实。但在相当长的时间内，它在其所擅长的领域里仍会占举足轻重的一席之地。如果C能借鉴C++的 命名空间、重载、异常处理和STL等非OOP的特征，它的生命力绝不会比任何OOP语言弱。附带说一句，C虽然没有直接支持OOP的语法，但经过适当的设计还是能实现OOP的<a class="link" href="#note2"><sup>[2]</sup></a>。”
        </p><p>
            引号咨询道：“关于C语言的学习，您有何建议？”
        </p><p>
            “精读K&amp;R的《The C Programming Language》，此书不过200多页，堪称C语言的剑诀。其中的R即Dennis Ritchie，是C的创造者，同时也是Unix的缔造者之一，是真正的大师。如今的大师，同博士、教授、院士等头衔一样，严重地通货膨胀了。”冒号不无感慨。
        </p><p>
            问号尖锐地问：“C++既保持了C的底层开发能力，又引入了OOP，C的处境想必更加艰难吧？”
        </p><p>
            冒号坦承：“这是不假。C++成功的一个重要因素是对C语言的兼容，由此吸引了大批的C程序员。但这不是没有代价的，C++在兼容C的同时也保留了C的许多缺陷。Java成功的地方有很多，一个不容忽视的因素是它彻底摆脱了与C兼容的桎梏。由于C++对C的改革不彻底，又过于庞杂，并且效率上不如C，这使得C仍有其生存空间。略有讽刺意味的是，对C++批判最激烈的往往来自C的社区，比如Linux之父Linus Torvalds就曾激烈地批判过C++。”
        </p><p>
            “Linus？那可是我的偶像呢！”叹号惊讶道。
        </p><p>
            冒号劝诫：“如果你因为是他的粉丝而后悔学C++，那就是为他人的偏执买单，不管那人名气有多大。”
        </p><p>
            句号指出：“C++最为人诟病的地方有：语法过于复杂，学习曲线陡、开发效率低；支持的范式过多；OOP不彻底；反射（reflection）功能不足；支持指针操作导致安全隐患；没有自动垃圾回收，容易内存泄漏；没有线程支持；没有丰富的标准库支持图形界面、网络编程等。”
        </p><p>
            “罪状不少哇！这些说法都有一定道理，但有些也有失公允。且听我一一道来。”冒号当起了辩护律师，“C++比较复杂这点没错，Stroustrup说过一句耐人寻味的话： 一种语言不够复杂是因为它还不够成熟。成人肯定比儿童复杂，因为他要承担更大的责任。大家不妨看看Java从1.0到即将问世的7.0、C#从1.0到即将的4.0的发展过程，是否应证了这一点？当然C++的复杂度的确高于其他语言，但如果不执着于奇技淫巧，它绝非高不可攀。C++的开发效率相比Java与C#，差距主要在两个方面：一是标准库不够完善，二是需要手工回收垃圾。关于前者，的确是C++的一大软肋，标准库竟然连企业应用中最常用的图形界面、网络编程、数据库处理、多线程等都不能涵盖，严重障碍了生产力。其实C++也有苦衷，不像Java和C#那样有大公司的鼎力支持，只靠效率极为低下的标准委员会来维护。98年的一个标准直到03年还在修订，下一个标准至少要到09年。连Stroustrup都在哭穷，声称没有足够的人力和时间来开发标准库，可为何广受赞誉的Boost库至今仍徘徊在标准门外？考虑到Boost的创办人大多出自标准委员会，其他无此背景的类库恐怕更难登C++之大堂了。相比之下D语言更惨，虽然天生丽质，苦无豪门青睐，只好一直待字闺中。”
        </p><p>
            叹号感慨：“金钱才是技术的最大推动力啊！”
        </p><p>
            “话糙理不糙。”冒号也很无奈，“再来谈谈有关自动垃圾回收的问题。在C++中，程序员也不是非得手工清理垃圾不可的。更好的办法是遵循RAII的惯用法（idiom）<a class="link" href="#note3"><sup>[3]</sup></a>，通过<span class="term">智能指针</span>（smart pointer）来解决内存释放问题。”
        </p><p>
            逗号听不明白：“什么是RAII？”
        </p><p>
            “RAII是Resource Acquisition Is Initialization的缩写，直译为‘资源获取即初始化’。”冒号解释，“其实更准确的叫法应该是RRIF（Resource Release Is Finalization），即‘资源释放即终结化’<a class="link" href="#note4"><sup>[4]</sup></a>。其思想是：将资源的取放与某一对象的生命周期绑定，初始化对象时获取资源，终结化对象时释放资源。用户代码不再直接管理资源，只需控制相应的对象即可。这样代码得以简化，资源的有效性也得以保障，并且还是<span class="term">异常安全的</span>（exception-safe）<a class="link" href="#note5"><sup>[5]</sup></a>。”
        </p><p>
            问号猜想：“在Java中没有这种用法，是因为它已经有了垃圾回收器吗？”
        </p><p>
            冒号摇摇头：“问题的关键不在这里。资源不只限于内存，还包括文件、线程锁、数据库连接等等，这些都不是垃圾回收器所能解决的。看看Java的数据库应用代码吧，对于那些频繁出现的被try/catch/finally包裹的resultset.close()、statement.close()、connection.close()，你是习以为常呢，还是不胜其烦？C#的设计者显然意识到这一点，专门提供了using语句来简化释放资源（IDisposable）的代码。”
        </p><p>
            逗号眼睛一亮：“如果采用RAII的技巧，这些都可以省去了吗？”
        </p><p>
            冒号再次摇头：“可惜Java不像C++或D那样，能在栈（stack）上创建对象。栈对象有一个特点，一旦超出其作用范围，便自动释放内存。在此之前会调用<span class="term">析构函数</span>（destructor），后者继而调用释放资源的代码。”
        </p><p>
            几声叹息清晰可闻。
        </p><p>
            冒号续道：“另一方面，尽管自动垃圾回收机制逐渐为大众所接受——据说C++0x也将部分地支持它——但这种机制也存在缺陷。比如一个Java程序如果在某一时段极耗内存，由于自动垃圾回收的不定时性，不能保证及时清理内存，可能会抛出OutOfMemoryError的错误。对于内存有限的系统或实时系统来说，这绝对是一个致命的软肋。C++不支持自动垃圾回收，正是基于这些方面的考虑。Stroustrup非常顾虑自动垃圾回收带来的时间和空间上的过多开销，并且担心它会影响C++完成其所肩负的底层任务。另外，千万不要以为有了自动垃圾回收机制就一劳永逸、万事大吉了。Java程序一样会有内存泄漏，其几率甚至可能比C++的更大，因为C++程序员对此更有戒心，而Java程序员大多被惯坏了，环保意识要淡薄得多。”
        </p><p>
            问号直奔要害：“您如何看待C与C++中的指针？”
        </p><p>
            冒号欣然接招：“指针是C与C++最大的特色，其他语言要么不支持，要么支持得有限。C与C++可以说是成也指针，败也指针。用得好可以是削铁如泥的神兵利器，用得不好则可能是自我毁灭的罪恶渊薮。但由于二者定位于系统语言，而指针对于底层操作是必不可少的。同样道理，二者的数据类型的转换比其他静态类型语言更自由，也是源出于此。”
        </p><p>
            句号总结：“<span class="strong"><strong>能力越大，责任越大，风险越大</strong></span>。”
        </p><p>
            “正是此意！”冒号重重地敲了一下桌子，“此话既适用于编程语言，也适用于程序员。至于C++缺少对反射功能的支持，也是因为追求效率，不愿在元数据上花时间和空间。说到C++支持的范式过多，程序员过于自由，代码不标准难维护，这就如同埋怨餐馆提供的菜式过多以致难以摆出一桌酒席一样可笑。最后，指责C++不是100％OOP的说法更是荒谬至极。OOP又不是金子，含量越高越好。<span class="strong"><strong>试图把一切都装进OOP的箱子里的想法无异于削足适履</strong></span>。典型的如Java中的Math类，逻辑上压根儿就不存在什么Math对象，清一色的static方法和常量就是最好的讽刺。在C++中只要在math的namespace中定义一些自由函数就可以了，自然而简洁。作为一个佐证，Java于J2SE5.0引进了<span class="term">静态导入</span>（static import）机制<a class="link" href="#note6"><sup>[6]</sup></a>，C#也在2.0增加了<span class="term">静态类</span><a class="link" href="#note7"><sup>[7]</sup></a>（static class），不仅在<span class="emphasis"><em>形式上</em></span>简化了代码，也在<span class="emphasis"><em>思维上</em></span>容忍了非OOP的过程式。”
        </p><p>
            引号发觉：“您好像把对C++所有的责难都化解了。”
        </p><p>
            “可恨之人必有可怜之处嘛。”冒号俗语反用，“其实C++仍有不少亟待改进之处，D语言就是很好的启示。D语言的提供了<span class="emphasis"><em>可控制的</em></span>垃圾回收器；支持线程同步；支持<span class="term">动态数组</span>（dynamic array）；支持<span class="term">嵌套函数</span>（nested function）；支持<span class="term">契约式设计</span>（design by contract）；废除了C与C++ 中令人头痛的<span class="term">头文件</span>（header file）等等。这些都是C++程序员梦寐以求的特征。”
        </p><p>
            逗号很奇怪：“为什么D语言名气这么小？”
        </p><p>
            句号吟道：“千里马常有，而伯乐不常有，大腕伯乐更稀有。”
        </p><p>
            众乐。
        </p><p>
            冒号拔高了调门：“既然系统语言主要为底层系统的开发服务，这就决定了它们的理念是：<span class="strong"><strong>优化机器的时间而不是人的时间，优化机器的记忆而不是人的记忆；假设编译器是愚蠢的而程序员是聪明的，因此赋予程序员更多的权利、义务与责任</strong></span>。无视这种背景和理念而去与其他语言相较，完全是不着筋节，不值一哂。当然这并不排斥系统语言用于应用开发，尤其是C++和D语言。需要强调的是，常见的‘C/C++’的说法很不科学。C与C++虽有千丝万缕的联系，但一个简单，一个复杂；一个纯过程式，一个集过程式、对象式、泛型式和元编程于一体。貌合神离，不宜混为一谈。”
        </p><p>
            叹号一个问题憋了半天，不吐不快：“我有一个问题：如今电脑性能这么高，C与C++如此强调程序的性能和效率还有必要吗？”
        </p><p>
            “绝对有必要！”冒号斩钉截铁，“其一、纵向看，用户的耐心与电脑的性能成反比，早年一个386人们就满足了，如今却忍受不了586；以前16M内存就不错了，现在1G都嫌小。其二、横向比，占用资源过多、运行相对缓慢的软件竞争力也低。其三、在一些应用领域如人工智能、大型计算等方面，普通电脑的性能还远远不能满足要求，超级计算机的存在就是明证。其四、仍有些程序跑在资源有限的主机上，比如嵌入式系统。”
        </p><p>
            引号再次要求：“能推荐一些C++方面的书吗？”
        </p><p>
            冒号直言相告：“学好C一本书足矣，学好C++即使推荐十本仍有遗珠之憾。可以说C++是苦了编程者，甜了著书人。开个小书单：初级——《C++ Primer》和《Thinking in C++》；中级——《The C++ Programming Language》和《Effective C++》系列；高级——《The C++ In-Depth》系列。这里还要特别推荐一下《The Design and Evolution of C++》，从中你可以看到 C++的设计和演变的来龙去脉，极具启发性。其他的C++精品书籍还有不少，恕不一一列举了。C++是匹无辔无鞍的野马，看似桀骜不驯，若能顺性而御，必能足踏飞燕，行千里而不劳。”
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    更官方的说法是“#”来自音乐中的高半音符号。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    比如文献【4】设计了一种用C来实现OOP的机制。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    RAII是由Bjarne Stroustrup首先提出的，参见文献【2】。
                </p></li><li class="listitem"><p><a name="note4"></a>
                    说它更准确，是因为资源获取的代码不一定需要出现在constructor中，但资源释放的代码一定出现在destructor中。
                </p></li><li class="listitem"><p><a name="note5"></a>
                    指即使发生异常（exception）也不会导致资源泄露。
                </p></li><li class="listitem"><p><a name="note6"></a>
                    比如，在静态导入Math类（import static java.lang.Math.*;）后，代码中可以直接调用sqrt、log、max等数学方法，不再需要“Math.”的前缀了。
                </p></li><li class="listitem"><p><a name="note7"></a>
                    静态类只能拥有静态成员，不能实例化，不能被继承，也不能继承除Object之外的类或接口。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    C++对C语言的兼容是其成功的一个重要因素，但同时也继承了C的一些缺陷。
                </p></li><li class="listitem"><p>
                    C++设计者没有直接支持自动垃圾回收，是担心它造成过大的时空开销，同时会削弱底层开发能力。
                </p></li><li class="listitem"><p>
                    除了手工释放内存外，C++提倡运用RAII原则解决包括内存在内的资源管理问题。
                </p></li><li class="listitem"><p>
                    C与C++对指针的全面支持和宽松的类型转换限制，均出于底层系统开发的需要。
                </p></li><li class="listitem"><p>
                    C可以借鉴C++的 命名空间、重载、异常处理和STL等非OOP的特征。
                </p></li><li class="listitem"><p>
                    D语言提供了可控制的垃圾回收器，支持线程同步、动态数组、嵌套函数和契约式设计，并废除了头文件和前置声明（forward declaration）。
                </p></li><li class="listitem"><p>
                    在程序性能与生产效率之间，系统语言更看重前者，它们在赋予程序员更多的权利的同时，也带给程序员更多的负担。
                </p></li><li class="listitem"><p>
                    程序的性能和效率永远是重要的。一方面，用户对软件性能的期望越来越高；另一方面，有时硬件性能与软件需求并不匹配：有些应用（如人工智能、大型计算）对程序的性能和效率要求极高，有些系统（如嵌入式系统）的资源十分有限。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Bjarne Stroustrup．The Design and Evolution of C++．Reading, MA：Addison-Wesley，1994．219-222
                </p></li><li class="listitem"><p>
                    Bjarne Stroustrup．The C++ Programming Language，Special ed.．Reading, MA：Addison-Wesley，2000．364-387
                </p></li><li class="listitem"><p>
                    Walter Bright．D Programming Language．<a class="link" href="http://www.digitalmars.com/d/" target="_top">http://www.digitalmars.com/d/</a>
                </p></li><li class="listitem"><p>
                    Axel Tobias Schreiner．Object-oriented Programming with ANSI-C．<a class="link" href="http://www.planetpdf.com/codecuts/pdfs/ooc.pdf" target="_top">http://www.planetpdf.com/codecuts/pdfs/ooc.pdf</a>
                </p></li></ol></div></div></div><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F29%2Fcolon-class-6_1%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A76.1%EF%BC%9A%E7%B3%BB%E7%BB%9F%E8%AF%AD%E8%A8%80">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/29/colon-class-6_1/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>冒号课堂§5.4：语言误区</title>
		<link>http://blog.zhenghui.org/2009/09/27/colon-class-5_4/</link>
		<comments>http://blog.zhenghui.org/2009/09/27/colon-class-5_4/#comments</comments>
		<pubDate>Sun, 27 Sep 2009 00:50:01 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[宗教]]></category>
		<category><![CDATA[架构师]]></category>
		<category><![CDATA[程序员]]></category>
		<category><![CDATA[编程语言]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=457</guid>
		<description><![CDATA[<b>语言误区</b>——语言的宗教情结（<em>关于编程语言认识上的一些误区</em>）<br/>
•	如果说编程范式是一种文化，那么编程语言更像是一种宗教——尽管它本不该是<br/>
•	语言只有两种：一种怨声载道，一种无人问津<br/>
•	对待一门语言的态度应该是：与其抱怨争执，不如扬长避短<br/>
•	过分拔高一种语言与抹煞语言之间的差别是两种极端，皆为秕言谬说<br/>
•	这些人若有幸拜关公为师，他们最艳羡的一定他的赤兔马和青龙偃月刀，或许还会抹红脸蓄长须什么的，就是不太愿学他的盖世武功<br/>
•	理想的架构师应当如文学大师，既有恢弘大气的构思，又有细腻深刻的笔法；应当如统军大帅，既有运筹帷幄的韬略，又有冲锋陷阵的武功]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第五课 语言小谈(4)</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="语言误区"><div class="titlepage"><div><div><h1 class="title"><a name="id592979"></a>5.4 语言误区——语言的宗教情结</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>关于编程语言认识上的一些误区</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>爱而不知其恶，憎而遂忘其善</p></div><div class="attribution"><span>—<span class="attribution">《吴兢•贞观政要》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    如果说编程范式是一种文化，那么编程语言更像是一种宗教——尽管它本不该是
                </p></li><li class="listitem"><p>
                    语言只有两种：一种怨声载道，一种无人问津
                </p></li><li class="listitem"><p>
                    对待一门语言的态度应该是：与其抱怨争执，不如扬长避短
                </p></li><li class="listitem"><p>
                    过分拔高一种语言与抹煞语言之间的差别是两种极端，皆为秕言谬说
                </p></li><li class="listitem"><p>
                    这些人若有幸拜关公为师，他们最艳羡的一定他的赤兔马和青龙偃月刀，或许还会抹红脸蓄长须什么的，就是不太愿学他的盖世武功
                </p></li><li class="listitem"><p>
                    理想的架构师应当如文学大师，既有恢弘大气的构思，又有细腻深刻的笔法；应当如统军大帅，既有运筹帷幄的韬略，又有冲锋陷阵的武功
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>为什么那么多人对某些编程语言都有浓厚的宗教情结？</p></li><li class="listitem"><p>存在至高无上的语言吗？</p></li><li class="listitem"><p>“语言不过是工具，其实都差不多”。这种论调正确吗？</p></li><li class="listitem"><p>IDE、框架、设计工具等比语言更重要吗？</p></li><li class="listitem"><p>语言是低级的代名词，设计是高级的代名词吗？</p></li><li class="listitem"><p>架构师就不关心语言了吗？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            “最后该谈谈你们最为关心的语言问题了。”冒号环视一番，众人眼球的瓦数显见增大，“如果说编程范式是一种文化，那么编程语言更像是一种宗教——尽管它本不该是。每种流行的语言都有大批忠实的信徒，随时可能与其他的信徒发生宗教战争。”
        </p><p>
            逗号深有同感：“周围和网上关于语言的争论从来不绝于耳，志不同道不合者动辄恶语相向。”
        </p><p>
            提起这些，冒号不免有些忿忿然：“这些信徒或准信徒们认为他们所崇拜的语言鹤立鸡群，远比其他语言高明得多，恨不得成为全天下程序员的通用语言。对其他语言的使用者，或居高临下地同情，或不屑一顾地讥讽。无知与偏见总是相辅相成的，他们中的绝大多数顶多熟悉一两种语言，其他的或浅尝辄止、或道听途说，却敢妄评优劣，岂不可笑之极？”
        </p><p>
            引号点头称是：“是啊，没有深入的了解，怎会有深入的比较。”
        </p><p>
            冒号进而尖锐地指出：“从心理学上分析，一个人在某种观点形成后，会通过自我的暗示和倾向性的证据不断地强化这种观点，并对其他观点本能地选择性失明。这背后折射的其实是一种懒人心态——认定自己掌握的语言是最好的，便不必费事再学其他语言了；这更是一种弱者心态——无论是耿耿忠心的铁杆卫士，还是振振有词的辩护律师，一旦丧失<span class="strong"><strong>自我批判的勇气和精神</strong></span>，声嘶力竭的挞伐只能反证他们的偏狭浅薄与自信缺失。”
        </p><p>
            冒号刻意借辛辣十足的嘲讽再次传递精神的信号。
        </p><p>
            叹号道出苦衷：“只是真正掌握好一门语言已殊为不易，同时掌握几种就更难。学完一种语言再看另一种，怎么都觉得别扭。”
        </p><p>
            “这就是第一堂课所说的‘学会’与‘会学’的差距。”冒号挑明要害，“每种语言都有天然设计上的不同，当你用得很别扭时，恰恰说明没有真正掌握。正如刀法以劈为主，枪法以扎为主，你若反其道而行之，刀扎枪劈，能不别扭吗？如果愣拿双节棍当单节棍使，恐怕没砸到别人倒先砸晕自己了。可见不是兵器问题，而是招法问题。”
        </p><p>
            下面隐约传来周杰伦《双截棍》的调子。
        </p><p>
            问号注意到：“似乎不只是初学者，大师们也会对一些语言提出过尖锐的批评。”
        </p><p>
            冒号引用道：“C++的发明者Bjarne Stroustrup说过这样一句话，语言只有两种：一种怨声载道，一种无人问津（There are only two kinds of languages: the ones people complain about and the ones nobody uses）。”
        </p><p>
            众笑。
        </p><p>
            句号有所体会：“一种语言如果用者甚众，自有其可取之处。没有一种语言是完美的，爱之深者尚苛之切，何况其余者乎？”
        </p><p>
            冒号忽然问：“你们知道对一种语言最大的批判是什么吗？”
        </p><p>
            众人纷纷摇头。
        </p><p>
            “那就是发明一种与此语言有类似功用的新语言。”冒号语速放缓，“Stroustrup认为Simula太慢、BCPL又太底层，于是发明了C++；Gosling觉得C++用得不爽，于是发明了Java；微软恼恨Java，于是请Hejlsberg发明了C#；Matsumoto用了两年多的C++仍不顺手，于是发明了Ruby。如此这般，不一而足。”
        </p><p>
            叹号无奈地说：“那是牛人的批评方法，常人怎能办到？”
        </p><p>
            “没有能力发明语言，就老老实实地用别人的吧。”冒号酷酷地说，“对待一门语言的态度应该是：与其抱怨争执，不如扬长避短。”
        </p><p>
            引号顺势道：“按这种说法，编程语言的发展史就是一种批判史咯？”
        </p><p>
            冒号祭起辩证法：“从另一个角度看，发明一种语言也是对先前语言的一种最高的赞美。C++之于C，Java之于C++，C#之于Java，都是后者对前者的一种承认，哪怕是极不情愿的承认。批判与赞美，继承与发展，谓之扬弃。”
        </p><p>
            众人心想，语言课又改哲学课了。
        </p><p>
            冒号续道：“对于编程语言还有一种论调：语言只是一种工具，哪种都差不多。”
        </p><p>
            逗号接茬：“是啊，经常在论坛上看到一些高手这么说。”
        </p><p>
            “一群伪高手，是工具就差不多？能拿锤子当刀使吗？”冒号嗤之以鼻，“<span class="strong"><strong>过分拔高一种语言与抹煞语言之间的差别是两种极端，皆为秕言谬说</strong></span>。图灵奖获得者Alan Perlis曾说过：如果一种语言不能影响你对编程的看法，那么就不值得去了解。试想，一种没有独特魅力的语言如何吸引程序员趋之若骛？了解这些独特之处对于编程往往至关重要，如果沿袭以前语言的做法，会显得不伦不类甚至可能铸成大错。”
        </p><p>
            问号要求：“能说得具体点吗？”
        </p><p>
            冒号举例：“有人说，学C++要先学C；还有人说，学会了C，C++就不在话下了。”
        </p><p>
            叹号一惊：“难道不是吗？”
        </p><p>
            冒号解释：“其实C++的真正来源是Simula而不是C，向下兼容C只是因为C效率高、普及广。换句话说，C++与C形同而神异。学会了C当然对C++有一定帮助，但若不能理解C++的OOP思想，那么C的背景反而是一种障碍。”
        </p><p>
            逗号想当然：“C++与Java都是OOP语言，差别该不大了吧？”
        </p><p>
            冒号再次否定：“不同编程范式的语言差别固是不可以道里计，即使同一范式的语言也是千差万别。一个纯粹的C++程序员用Java编程，会非常不习惯没有指针运算、没有内存控制、没有运算符重载、没有自由函数等等。一个纯粹的Java程序员用C++编程，会极度不适应相对贫乏的标准库；会困惑于指针、引用、数组、字符串还有头文件等的用法；会毫不吝惜地在<span class="term">堆</span>（heap)上创建新对象，并且从来不去释放它们。这些概念或用法都是贯穿整个程序始终的，差别能不大吗？”
        </p><p>
            叹号听罢叹曰：“做一个好的程序员还真不容易。”
        </p><p>
            “如果容易，我们开这个班做什么？” 冒号笑道，“提一个问题，程序员最不能离开的应用软件是什么？”
        </p><p>
            逗号顺嘴道：“当然是IDE了。”
        </p><p>
            引号纠正：“应该是编辑器，有些程序员用vi甚至记事本来写程序。”
        </p><p>
            冒号插一句：“有人还在命令行下写程序。”
        </p><p>
            叹号眼瞪得溜圆：“怎么可能？”
        </p><p>
            冒号眉毛一挑：“当然可能，一些简单的程序完全可以在命令行下完成，然后重定向（redirect）到一个文件中或者直接编译执行。这种情况虽有些极端，对于那些离开IDE就没法编程的人来说更是不可思议，但至少说明编程离开编辑器还是有可能的<a class="link" href="#note1"><sup>[1]</sup></a>。”
        </p><p>
            句号突然明白了：“是编译器！”
        </p><p>
            “不错，是编译器或解释器。”冒号作了一点修正。
        </p><p>
            问号有点茫然：“为什么谈这个呢？”
        </p><p>
            “因为编译器或解释器是语言实现的标志。”冒号提高了声调，“我想借此说明一个简单的道理：<span class="strong"><strong>对一个程序员而言，编程语言乃立身之本</strong></span>。许多人偏偏本末倒置，常常为在IDE、框架、设计工具等中挖掘到某些新功能而欣喜不已，或者津津乐道于各种语言的优劣高下，却对正在使用的语言中大量的宝藏视而不见，与执金碗而行乞者何异？这些人若有幸拜关公为师，他们最艳羡的一定他的赤兔马和青龙偃月刀，或许还会抹红脸蓄长须什么的，就是不太愿学他的盖世武功。”
        </p><p>
            引号质疑：“我明白您是想修研强调内功的重要性，但似乎有些唯语言论，设计思想不是更重要吗？”
        </p><p>
            冒号补充道：“我所谈的语言，自然不是孤立的语法和用法，也包括背后的编程范式和设计思想。当然更高层的架构设计可能会脱离具体的语言，但那不在考虑之列，因为我们谈论的主体是程序员，而不是架构师。”
        </p><p>
            提到架构师，众人神往之情油然而生。
        </p><p>
            冒号看透了大家的心思：“架构师并没有多么神秘，他们也是从程序员过来的。也不要以为架构师就不关心语言了，相反需要对语言有更广博、更深刻的认识。理想的架构师应当如文学大师，既有恢弘大气的构思，又有细腻深刻的笔法；应当如统军大帅，既有运筹帷幄的韬略，又有冲锋陷阵的武功。那些在语言与低级之间、设计与高级之间毫不犹豫地划等号的人，多半高不成低不就，既不懂语言，也不懂设计。”
        </p><p>
            逗号仍有疑惑：“语言真有那么重要吗？IDE的一些集成工具可以辅助生成许多代码，或许到了某一天，拖拖鼠标、画些UML图之类的，程序就大功告成了。”
        </p><p>
            冒号哈哈一笑：“这不就是元编程吗？元编程也是用语言实现的。且不说你描绘的美景是否可能，即便实现了，程序员的任务也是用更高级的语言做更高级的编程——还是离不开语言。别忘了，技术含金量是与工资含金量成正比的，你永远需要比别人多一门扎实的功夫。程序员这门职业，你选择，你担当。好了，闲话打住，欲知在下如何评价各种编程语言，且听下回分解。”
        </p><p>
            众人听兴正浓之际，课堂却在说书式的结语中戛然而止了。
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    当然，命令行本身也可看作编辑器，比如Bash提供vi和emacs两种命令行编辑模式。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    凡事因了解而喜爱，因无知而憎恶。
                </p></li><li class="listitem"><p>
                    破除语言的宗教情结，保持自我批判的勇气和精神。
                </p></li><li class="listitem"><p>
                    过分拔高一种语言与抹煞语言之间的差别是两种极端观点，皆不可取。
                </p></li><li class="listitem"><p>
                    每种语言都有其特到之处和不足之处，与其抱怨争执，不如扬长避短。
                </p></li><li class="listitem"><p>
                    编程语言在批判与赞美中逐步发展。
                </p></li><li class="listitem"><p>
                    编程语言是程序员的立身之本。切不可本末倒置，忽视语言的学习，却热衷于挖掘IDE、框架、设计工具等的新功能。
                </p></li><li class="listitem"><p>
                    语言不等于低级，设计也不等于高级。
                </p></li><li class="listitem"><p>
                    架构师同样关心语言，并且需要对语言有更深更广的认识。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Bjarne Stroustrup．The Design and Evolution of C++．Reading, MA：Addison-Wesley，1994．19-25
                </p></li><li class="listitem"><p>
                    Alan Perlis．EPIGRAMS IN PROGRAMMING．<a class="link" href="http://www.cs.yale.edu/homes/perlis-alan/quotes.html" target="_top">http://www.cs.yale.edu/homes/perlis-alan/quotes.html</a>
                </p></li></ol></div></div></div>

<!-- below is edited manually -->
<strong><span style="font-family: 宋体">课后思考</span></strong>
<ul style="margin-top: 0cm; list-style-type: none">
    <li>
        05-01 程序员这个职业合适你吗？你在工作中胜任愉快吗？
    </li>
    <li>
        05-02 你认为理想的类型系统应该有哪些规则？
    </li>
    <li>
        05-03 你喜欢duck typing吗？它有何优点？如何防止它的误用和滥用？
    </li>
    <li>
        05-04 你是如何看待动态语言的？与静态语言相比，哪些是你所欣赏的，哪些是你所不满的？
    </li>
    <li>
        05-05 你最熟悉哪种编程语言？你认为它是最好的语言吗？
    </li>
    <li>
        05-06 对一门不熟悉的编程语言，你是乐于了解和学习它，还是本能地漠视或排斥它？
    </li>
    <li>
        05-07 爱可以不需要理由，恨却需要。能说说你恨某种语言的理由吗？你确信它们站得住脚吗？
    </li>
    <li>
        05-08 你是更愿意把时间花在编程工具的功能挖掘上，还是花在编程语言的深造学习上？
    </li>
</ul><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F27%2Fcolon-class-5_4%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A75.4%EF%BC%9A%E8%AF%AD%E8%A8%80%E8%AF%AF%E5%8C%BA">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/27/colon-class-5_4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>冒号课堂§5.3：动态语言</title>
		<link>http://blog.zhenghui.org/2009/09/25/colon-class-5_3/</link>
		<comments>http://blog.zhenghui.org/2009/09/25/colon-class-5_3/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 01:47:56 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[动态语言]]></category>
		<category><![CDATA[程序]]></category>
		<category><![CDATA[脚本]]></category>
		<category><![CDATA[脚本语言]]></category>
		<category><![CDATA[静态语言]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=455</guid>
		<description><![CDATA[<b>动态语言</b>——披着彩衣飞舞的脚本语言（<em>动态语言简谈</em>）<br/>
•	程序是为终端用户服务的，而脚本是为程序员服务的<br/>
•	动态语言秉承的一个理念是：优化人的时间而不是机器的时间<br/>
•	待静态语言披盔戴甲、备马抬枪之际，动态语言已衣袂飘飘，长剑出手了<br/>
•	当脚本语言披上动态语言的彩衣，昔日不起眼的毛毛虫便羽化成碟，开始飘舞在众人追逐的目光之中]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第五课 语言小谈(3)</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="动态语言"><div class="titlepage"><div><div><h1 class="title"><a name="id565672"></a>5.3 动态语言——披着彩衣飞舞的脚本语言</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>动态语言简谈</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>故凡天下之理，欲向动上求静，静上求动</p></div><div class="attribution"><span>—<span class="attribution">《蔡牧堂•发微论》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    程序是为终端用户服务的，而脚本是为程序员服务的
                </p></li><li class="listitem"><p>
                    动态语言秉承的一个理念是：优化人的时间而不是机器的时间
                </p></li><li class="listitem"><p>
                    待静态语言披盔戴甲、备马抬枪之际，动态语言已衣袂飘飘，长剑出手了
                </p></li><li class="listitem"><p>
                    当脚本语言披上动态语言的彩衣，昔日不起眼的毛毛虫便羽化成蝶，开始飘舞在众人追逐的目光之中
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>脚本与程序的区别是什么？</p></li><li class="listitem"><p>脚本语言有什么特点？为什么适合作粘合语言？</p></li><li class="listitem"><p>动态语言有什么特点？它与脚本语言究竟有什么分别？</p></li><li class="listitem"><p>动态语言也能用于大型应用开发吗？</p></li><li class="listitem"><p>动态语言会最终取代静态语言吗？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            叹号急不可耐地问：“现在可以谈动态语言了吧？”
        </p><p>
            冒号感言：“曾几何时，动态语言还只是陪太子读书的角色，那时候它们的名字是‘脚本语言’。近来却迅速崛起，俨然有与静态语言分庭抗礼之势。”
        </p><p>
            问号忍不住问道：“动态语言与脚本语言是一回事吗？”
        </p><p>
            “相比动态语言定义上的模糊，脚本语言的概念还是比较明确的。”冒号回避直接给出答案，“<span class="term">脚本</span>（script）的提法，是为了区别于一般的<span class="term">程序</span>（program）。Perl的发明者Larry Wall不愧为语言学家，对此有一个精彩的说法：‘A script is what you give the actors, a program is what you give the audience’。直译为：脚本是给演员看的，节目是给观众看的。此言妙在一语双关——program兼有‘节目’和‘程序’的意思。”
        </p><p>
            句号领会其意：“这里的演员指的是程序员，观众指的是用户。换言之，<span class="strong"><strong>程序是为终端用户服务的，而脚本是为程序员服务的</strong></span>。”
        </p><p>
            “正解！”冒号肯定道，“脚本最常见的形式是<span class="term">壳脚本</span>（shell script），在非Unix类的操作系统中也称为<span class="term">批处理文件</span>（batch file）。”
        </p><p>
            “批处理文件倒是很熟悉，壳脚本听起来就怪怪的。”逗号嘀咕着。
        </p><p>
            “那是因为你在Windows的世界里长大，听不惯Unix的方言。”冒号一语道破缘由，“操作系统的内核称为<span class="term">核</span>（kernel），出于安全考虑不便直接与用户交互，因此裹上一层<span class="term">壳</span>（shell），即人们常说的<span class="term">命令行解释器</span>（command line interpreter）。壳脚本是在壳上运行的脚本，扩展了命令行下可执行的命令。它最初主要是内建（built-in）命令的组合，用于<span class="emphasis"><em>系统程序</em></span>的调度，是系统管理员的必备武器。其后，壳脚本也发展到用于<span class="emphasis"><em>应用程序</em></span>的调度、连接、调试等，成为<span class="emphasis"><em>粘合</em></span>（glue）语言。”
        </p><p>
            逗号不禁有些疑问：“难道一般的程序语言如C之类的不能作此用吗？”
        </p><p>
            引号回应道：“这些语言通常需要‘编写－编译－链接－运行’的循环过程，十分繁琐。脚本语言编写后即可运行，快捷方便得多。”
        </p><p>
            冒号点点头：“不错，既然脚本主要用于整合其他程序，本身并不占用太多的资源，同时逻辑也不太复杂，因此脚本语言注重简洁、实用，语法要求不那么严格，性能上的要求也不高。除壳脚本外，还有一些专用于<span class="emphasis"><em>文本处理</em></span>（text processing）的语言或工具如AWK、sed和grep等，多用于读写配置文件和日志文件、过滤处理各种程序的输入和输出，对于整合各种程序也非常实用。随着对脚本语言需求的增长，其局限性日益突出，以Perl为代表的高级脚本语言便应运而生了。Perl在壳脚本、AWK、sed的基础上，融合了命令式的C与函数式的Lisp的特征，渐渐成为最流行的脚本语言之一。”
        </p><p>
            问号注意到：“JavaScript是浏览器端的脚本，来路似乎有些不同。”
        </p><p>
            冒号解释道：“除了命令行程序外，脚本语言在其他的应用程序中也身影频现，如图形界面应用、多媒体应用、网络应用等。尤其是网络应用，成为滋生和繁荣脚本语言最肥沃的土壤。例如：Perl非常广泛地用于网络服务器端的CGI编程；PHP更是专为动态网页而设计的语言；Ruby虽与Java同岁，但真正开始风行得益于网络应用框架Ruby on Rails的成功；至于JavaScript，长期被边缘化为网页设计人员的语言，是web2.0的新宠AJAX真正将其带入程序员的视线。”
        </p><p>
            逗号有些好奇：“什么时候脚本语言变成了动态语言呢？”
        </p><p>
            “尽管动态语言并无确切的定义，但不是所有的脚本语言都能称作动态语言的——比如Bash之类的<span class="term">壳脚本语言</span>（shell script language）；另一方面，也不是所有的动态语言天生就是为脚本服务的——比如Lisp<a class="link" href="#note1"><sup>[1]</sup></a>。不妨这么理解，脚本语言以语言的<span class="emphasis"><em>实际用途</em></span>为标志，动态语言以语言的<span class="emphasis"><em>语法特征</em></span>为标志。”冒号回答，“单从<span class="emphasis"><em>用途</em></span>上看，一个脚本语言如果不再局限于命令行工具和粘合工具，从<span class="emphasis"><em>专用语言</em></span>发展为<span class="emphasis"><em>通用语言</em></span>，并能胜任复杂的应用开发，或许更有资格归为动态语言。”
        </p><p>
            句号发现：“动态语言似乎对字符处理都特别擅长。”
        </p><p>
            冒号道：“脚本语言与一般程序一个不同之处是，它一般是面向字符而非数值的，因为字符是最通用的接口，正好发挥其粘合作用，而数值运算对性能要求较高，多由核心程序来完成。动态语言继承了这个特点，并且除了<span class="term">正则表达式</span>（regular expression）外，为字符串、数组、列表、集合、映射等常用结构提供了丰富简洁的运算，远比静态语言依赖于库（library）的方便自然得多。” 
        </p><p>
            叹号问：“我们清楚了脚本语言中‘脚本’的来历，那动态语言中‘动态’又体现在何处呢？”
        </p><p>
            “问得好！”冒号闻言，正中下怀，“再从<span class="emphasis"><em>用法</em></span>上看，动态语言能在<span class="emphasis"><em>运行中</em></span>增加或改变数据结构、函数定义、对象行为或指令流程等。如果说动态类型语言的动态体现在类型上，动态语言的动态则体现在结构和功能上。相比而言，静态语言虽然也可能实现同样的效果，但既不方便也不自然<a class="link" href="#note2"><sup>[2]</sup></a>。另外不容忽视的一点是，动态语言大多是开源的，其本身的发展也更具动态性。” 
        </p><p>
            引号非常注重理论：“动态语言的语法特征有那些？”
        </p><p>
            “动态语言秉承的一个理念是：<span class="strong"><strong>优化人的时间而不是机器的时间</strong></span>。为提高人的生产率，宁肯牺牲部分的程序性能或者购买更高配置的硬件。由于<span class="strong"><strong>硬件相对于人件一直在贬值</strong></span>，该理念便有了合理的现实基础。”冒号讲述着，“从<span class="emphasis"><em>语法</em></span>上看，动态语言为了更好地粘合来自不同系统、不同语言的程序，对类型的要求一般不如静态语言那么严格，代码更加简洁自由，故而多为动态类型的和弱类型的，天然支持<span class="term">泛型式编程</span>。当然这不是绝对的，比如Groovy也支持静态类型，Scala完全是静态类型的，Python一般认为是强类型的。大多数动态语言支持eval函数，能动态执行任意字符串形式的代码，并有丰富的反射（reflection）机制，天然支持<span class="term">元编程</span>。动态语言很多还支持包括<span class="term">高阶函数</span>（high-order function）和<span class="term">闭包</span>（closure）等在内的<span class="term">函数式编程</span>。此外，大多动态语言也支持<span class="term">对象式编程</span>，如Python、Ruby、Perl 5、PHP 3等。”
        </p><p>
            句号补充道：“许多动态语言还支持<span class="term">过程式编程</span>和<span class="term">并发式编程</span>，简直把主要的编程范式一网打尽了！”
        </p><p>
            “其实Python、Ruby和Groovy等还可以进行<span class="term">切面式编程</span>，这对于支持元编程的动态语言来说非常自然，因为切面式编程一般都是通过元编程来实现的。”冒号进一步指出，“而<span class="term">逻辑式编程</span>语言的代表Prolog，同样有动态语言的特征。至于<span class="term">事件驱动式编程</span>嘛，对支持callback的语言来说都不是难事。”
        </p><p>
            引号高兴地看到：“九大编程范式无一漏网啊！”
        </p><p>
            叹号较为感性：“静态语言给人的感觉是沉稳持重，而动态语言则活泼轻快。如果同时用静态语言和动态语言编程，岂不培养出双重人格？”
        </p><p>
            “程序员本就是双重人格的。”冒号淡淡地说，“你总结得没错，两类语言的风格的确大相异趣：待静态语言披盔戴甲、备马抬枪之际，动态语言已衣袂飘飘，长剑出手了。不过，如果是应付强敌的长期大规模作战，静态语言还是有优势的。”
        </p><p>
            引号听声辨音：“这意味着动态语言不适用大型应用开发吗？“
        </p><p>
            “这么说未免有些武断。”冒号并不同意，“诚然，动态语言的语法比较宽松，相对容易出错。但也有人辩称，动态语言的代码量少于相应的静态语言，bug应该更少。有人认为动态语言调试不如静态语言方便，有人却说随着IDE的日益强大，出错几率和找错成本也在减少。谈到运行效率，动态语言虽然多为<span class="term">解释型语言</span>（interpreted language），但许多也提供了与Java类似的<span class="term">字节码编译</span>（bytecode compilation）甚至<span class="term">JIT编译</span>(just-in-time compilation)。动态语言在某方面甚至还更胜一筹：譬如一个类的接口如果发生变动，在静态语言中所有该类的子类和一些相关类都可能需要重新编译、连接，这在大型应用中是非常耗时的，而动态语言则大可不必，这当然不足为奇——在它眼里类结构本来就是能动态改变的。除此之外，越是大型的程序，越耗费人力和时间成本，客户需求的变化也越大，因而对程序的灵活性、适应性和开发周期提出了更高的要求。动态语言在这些方面比静态语言更有优势，并且还能作为<span class="term">快速原型</span>（rapid prototyping）开发的工具。”
        </p><p>
            “快速原型开发？”问号一脸的疑惑。
        </p><p>
            冒号简作介绍：“这是一种软件开发的方式。举例来说，为了快速搭建一个系统，以适应不断变化的客户需要，可以先采用开发效率更高的动态语言。在交付时再将其转化为编译型的静态语言。如果系统对性能的要求不高，这种转化至多是局部的。有的干脆一字不易，不仅省了当下的时间，以后维护起来也更方便。”
        </p><p>
            逗号耍起了贫嘴：“这就叫：替补变成了主力，配角变成了主角，媳妇熬成了婆婆。”
        </p><p>
            叹号开始担忧起来：“听您这意思，动态语言优点突出而弱点并不突出，这样下去静态语言还有市场吗？”
        </p><p>
            冒号坦然道：“动态语言小快灵的风格的确吸引了越来越多人的注意，也渐渐走入静态语言的世界。Java平台和.NET平台不仅为Ruby和Python等动态语言铺设了跑道，而且为培植诸如Groovy等动态语言提供了土壤。同时，Java和C#本身也融进了越来越多的动态特征。”
        </p><p>
            句号断言：“静态语言这种融合性结合内在的安全性、稳定性，以及较高的性能、成熟度和接受度，都决定了它不可能被动态语言完全取代。”
        </p><p>
            “对！”冒号坚定地表示赞同，“当脚本语言披上动态语言的彩衣，昔日不起眼的毛毛虫便羽化成蝶，开始飘舞在众人追逐的目光之中。但静态语言也绝不会淡出人们的视线，它如矫健的苍鹰，依然有搏击长空的雄力。程序员只要保持严谨的作风和开放的心态，既有稳如泰山的马步，又有一跃凌空的飞腿，静如处子，动如脱兔，如履平地般游走于高高的梅花桩上，绝无跌落之虞。” 
        </p><p>
            一股豪情在众人心中荡漾开来。
        </p><p>
            冒号看了看时间，敛起眼中精光，同时收起话匣：“关于动态语言，今天还是先简单谈到这里吧。”
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    Lisp本身以及一些变种如Emacs Lisp、AutoLISP等也能作为脚本语言，但那毕竟不是Lisp语言的初衷。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    一些设计模式（如装饰模式、职责链模式、状态模式、访问者模式等）就是为了赋予静态语言一定的动态特征。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    程序是为终端用户服务的，脚本是为程序员服务的。
                </p></li><li class="listitem"><p>
                    脚本语言一般是解释型语言，不需要通过“编写－编译－链接－运行”的循环圈，便利快捷，加之简洁宽松的语法、面向字符的特性以及较强的文本处理能力，尤其适合作为粘合语言，多用于系统管理和集成。
                </p></li><li class="listitem"><p>
                    脚本语言与动态语言尽管并不完全重合，但更多地还是提法上的区别。前者强调作为命令行工具和粘合工具的语言用途，后者强调动态的语言特征。当脚本语言不再局限于粘合语言，从专用语言发展为通用语言，并且胜任复杂的应用开发的时候，动态语言的提法显然更加合理。
                </p></li><li class="listitem"><p>
                    动态语言能在程序运行期间改变数据结构、函数定义、对象行为或指令流程等，相比静态语言在结构和功能上的更具动态性。
                </p></li><li class="listitem"><p>
                    动态语言重在优化人工时间而非机器时间，因此相比静态语言，其开发效率较高，但运行效率较低。
                </p></li><li class="listitem"><p>
                    动态语言的以下特点决定了它在大型应用开发中的价值：代码量较少，从一定程度减轻了维护难度；不少提供了字节码编译或JIT编译，弥补了运行效率上的不足；一些模块的结构和功能上的变化不会导致相关模块的重新编译和连接；具有灵活、适应力强和开发周期短的特点，能快速响应客户需求的变化，并且适合快速原型开发。
                </p></li><li class="listitem"><p>
                    静态语言安全稳定、性能优越、成熟普及，并且逐渐开始吸纳动态语言的一些优点，这些都决定了它不可能被后者完全替代。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Wikipedia．Dynamic programming language．<a class="link" href="http://en.wikipedia.org/wiki/Dynamic_language" target="_top">http://en.wikipedia.org/wiki/Dynamic_language</a>
                </p></li><li class="listitem"><p>
                    David Ascher．Dynamic Languages—ready for the next challenges, by design．<a class="link" href="http://www.activestate.com/corporate/publications/ActiveState_Dynamic_Languages.pdf" target="_top">http://www.activestate.com/corporate/publications/ActiveState_Dynamic_Languages.pdf</a>
                </p></li></ol></div></div></div><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F25%2Fcolon-class-5_3%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A75.3%EF%BC%9A%E5%8A%A8%E6%80%81%E8%AF%AD%E8%A8%80">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/25/colon-class-5_3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>冒号课堂§5.2：数据类型</title>
		<link>http://blog.zhenghui.org/2009/09/23/colon-class-5_2/</link>
		<comments>http://blog.zhenghui.org/2009/09/23/colon-class-5_2/#comments</comments>
		<pubDate>Wed, 23 Sep 2009 06:52:28 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[Duck类型]]></category>
		<category><![CDATA[动态类型]]></category>
		<category><![CDATA[弱类型]]></category>
		<category><![CDATA[强类型]]></category>
		<category><![CDATA[数据类型]]></category>
		<category><![CDATA[类型安全]]></category>
		<category><![CDATA[静态类型]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=445</guid>
		<description><![CDATA[<b>数据类型</b>——规则与变通（<em>关于数据类型的讨论</em>）<br/>
•	Duck类型的哲学是：名义不重要，重要的是能力<br/>
•	将一个会叫会游的家伙放进池塘看起来不算坏主意，但如果一艘轮船趁机也轰隆隆地开了进来，事情恐怕就不那么美妙了<br/>
•	静态类型检查类似“疑罪从有”的有罪推定制，动态类型检查类似“疑罪从无”的无罪推定制<br/>
•	尽可能守规则，必要时求变通<br/>
•	规则如裤带，过于宽松和过于束缚都不好  <!--more-->]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第五课 语言小谈(2)</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="数据类型"><div class="titlepage"><div><div><h1 class="title"><a name="id600625"></a>5.2 数据类型——规则与变通</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>关于数据类型的讨论</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>操纵于规矩之中，神明于规矩之外</p></div><div class="attribution"><span>—<span class="attribution">《俞震•古今医案按》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    Duck类型的哲学是：名义不重要，重要的是能力
                </p></li><li class="listitem"><p>
                    将一个会叫会游的家伙放进池塘看起来不算坏主意，但如果一艘轮船趁机也轰隆隆地开了进来，事情恐怕就不那么美妙了
                </p></li><li class="listitem"><p>
                    静态类型检查类似“疑罪从有”的有罪推定制，动态类型检查类似“疑罪从无”的无罪推定制
                </p></li><li class="listitem"><p>
                    尽可能守规则，必要时求变通
                </p></li><li class="listitem"><p>
                    规则如裤带，过于宽松和过于束缚都不好
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>动态语言与动态类型语言是一回事吗？</p></li><li class="listitem"><p>数据类型有哪两个要素？其意义何在？</p></li><li class="listitem"><p>什么是动态类型和静态类型？它们的区别是什么？各有什么优缺点？</p></li><li class="listitem"><p>什么是鸭子类型（duck typing）？它有什么优缺点？</p></li><li class="listitem"><p>什么是强类型与弱类型？什么是类型安全的？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            待教室平静下来，冒号再度开腔：“在谈论动态语言之前，最好先澄清一下它与动态类型语言之间的区别。”
        </p><p>
            叹号讶然道：“它们不是一回事吗？一直以为动态语言是动态类型语言的简称呢。”
        </p><p>
            “有亲戚之名，却无血缘之亲。名称上相似，加之动态语言绝大多数确是动态类型语言，造成混淆实属在所难免，但二者之间并无必然联系——动态语言不一定是动态类型语言<a class="link" href="#note1"><sup>[1]</sup></a>，动态类型语言也不一定是动态语言<a class="link" href="#note2"><sup>[2]</sup></a>。”冒号飞跑的舌头几乎绊蒜，同时把众人的脑子搅成了一锅粥。
        </p><p>
            见势不妙，冒号改用迂回战术：“我们不妨再谈开些，大家对<span class="term">数据类型</span>是如何理解的？”
        </p><p>
            逗号随口道：“数据类型不就是数据的种类吗？”
        </p><p>
            众人暗笑：说了跟没说差不多。
        </p><p>
            冒号说道：“数据类型包含两个要素：一个是<span class="emphasis"><em>允许取值的集合</em></span>，一个是<span class="emphasis"><em>允许参与的运算</em></span>。例如int类型在Java中既定义了介于-2<sup>31</sup>和2<sup>31</sup> &#8211; 1之间的整数集合，也定义了该集合上的整数所能进行的运算。现在的问题是：数据类型的意义何在？”
        </p><p>
            句号回答：“限定一个变量的数据类型，就意味着限制了该变量的取值范围和所参与的运算，这从一定程度上保证了代码的<span class="emphasis"><em>安全性</em></span>。”
        </p><p>
            冒号追问：“还有吗？”
        </p><p>
            句号略作思考后说：“用户自定义的数据类型，如C中的结构和Java中的类或接口，赋予数据以逻辑内涵，提高了代码的<span class="emphasis"><em>抽象性</em></span>。”
        </p><p>
            “精辟！”冒号赞道，“数据类型既有针对机器的<span class="emphasis"><em>物理意义</em></span>，又有针对人的<span class="emphasis"><em>逻辑意义</em></span>。前者用于进行<span class="emphasis"><em>底层</em></span>的内存分配和数值运算等，后者用于表达<span class="emphasis"><em>高层</em></span>的逻辑概念。既然类型如此重要，类型检查就必不可少了<a class="link" href="#note3"><sup>[3]</sup></a>。所谓<span class="term">动态类型语言</span>（dynamic typing language），正是指类型检查发生在<span class="emphasis"><em>运行期间</em></span>（run-time）的语言。”
        </p><p>
            “那<span class="term">静态类型语言</span>（static typing language）自然是类型检查发生在<span class="emphasis"><em>编译期间</em></span>（compile-time）的语言咯。”引号接话道。
        </p><p>
            冒号回应：“一般的说法是这样，但我更愿意将‘编译期间’四个字改为‘运行之前’，否则容易让人<span class="emphasis"><em>误解</em></span>为静态类型语言一定是<span class="term">编译型语言</span>（compiled language）。”
        </p><p>
            问号问道：“是否可以这么说：静态类型语言需要变量声明，而动态类型语言则不需要？”
        </p><p>
            “这话只对了一半。”冒号评论，“动态类型语言固然不需要显式的变量声明（explicit declaration），一些静态类型语言有时也不需要。典型的如ML、Haskell之类的函数式语言，编译器可以通过上下文来进行<span class="emphasis"><em>类型推断</em></span>（type inference）。另外，C#从3.0起也开始支持局部变量的类型推断。”
        </p><p>
            “如何进行类型推断？”问号有点丈二和尚摸不着头脑。
        </p><p>
            冒号打了个比方：“假设‘+’号只限于同类型的数据运算，那么从表达式a + 1中可以推出a是整型变量，从b + 1.0中推出b是浮点型变量，从c + “1”中推出c是字符串型变量。这些变量不必事先声明，但一旦类型被推断确定后，便不再更改。由于这些推断都是在程序运行之前进行的，因此仍属于静态类型。它既有动态类型的简洁性，又不失声明式静态类型的安全性，可谓裁长补短啊。”
        </p><p>
            叹号有些羡慕地说：“还是动态类型语言好，不仅不必声明变量，而且一个变量在不同地方还可以代表不同类型，多省事多方便啊！”
        </p><p>
            冒号微微颔首：“虽然这种机制也有为人诟病之处，但不可否认，动态类型语言的确有它的优势：简明、快捷、灵活，并且天然具有泛型（generic）特征。值得一提的是，动态类型有一种被称作<span class="term">鸭子类型</span>（duck typing）的形式。”
        </p><p>
            逗号感到有趣：“鸭子类型？很滑稽的名字。”
        </p><p>
            “这种类型通俗的说法是：如果一个对象既会走鸭步又会呷呷叫，何妨将其视作鸭子呢？”冒号说着投影出一段Ruby代码——
        </p><div class="informalexample"><pre class="programlisting">
class Duck                      #会叫会游的鸭
    def shout
        puts '呷呷呷'
    end
    def swim
        puts '鸭泳'
    end
end

class Frog                      #会叫会游的蛙
    def shout
        puts '呱呱呱'
    end
    def swim
       puts '蛙泳'
    end
end

def shoutAndSwim(duck)          #让一只会叫会游的家伙边叫边游
    duck.shout
    duck.swim
end

shoutAndSwim(Duck.new)          #让一只鸭边叫边游
shoutAndSwim(Frog.new)          #让一只蛙边叫边游 </pre></div><p>
            冒号继续讲解：“在Smalltalk、Python和Ruby等动态类型的OOP语言中，只要一个类型具有shout和swim的方法，它就可以为shoutAndSwim所接受。这在C++、Java、C#等静态类型语言中是不可能的<a class="link" href="#note4"><sup>[4]</sup></a>，除非鸭和蛙在同一继承树上，或者二者均<span class="emphasis"><em>显式</em></span>实现了一个包含shout和swim的公用接口。”
        </p><p>
            句号敏锐地指出：“C++是静态类型语言，但它的模板也可实现类似功能，并不需要引入继承关系。”
        </p><p>
            “说得很对！但请接着看下去。”冒号又放出一段投影——
        </p><div class="informalexample"><pre class="programlisting">
class Cock                      #会叫不会游的鸡
    def shout
        puts '喔喔喔'
    end
end
 
class Fish                      #会游不会叫的鱼
    def swim
        puts '自由泳'
    end
end

def shoutOrSwim(duck, flag)     #让一只会叫或会游的家伙叫或游
    flag ? duck.shout : duck.swim
end

shoutOrSwim(Cock.new, true)     #让一只鸡叫
shoutOrSwim(Fish.new, false)    #让一只鱼游 </pre></div><p>
            “这里鸡没有swim的方法，鱼没有shout的方法。若采用C++的模板，shoutOrSwim是无法通过编译的。但在支持Duck 类型的语言中，只要在<span class="emphasis"><em>运行期间</em></span>不让鸡swim、让鱼shout——除非你突发奇想——一切平安无事。”冒号作了个OK的手势。
        </p><p>
            “动态类型语言真是越看越可爱。”叹号简直垂涎欲滴了。
        </p><p>
            “Duck类型的哲学是：名义不重要，重要的是能力，颇有些实用主义的味道。这种<span class="emphasis"><em>非继承性多态</em></span>为软件重用开启了新的窗口，同时也埋下了一些陷阱。由于Duck类型的接口组合是<span class="emphasis"><em>隐性的</em></span>，其使用者需要比普通interface更小心以避免误用；其维护者也需要更小心以避免破坏客户代码；另外它也可能造成滥用——将一个会叫会游的家伙放进池塘看起来不算坏主意，但如果一艘轮船趁机也轰隆隆地开了进来，事情恐怕就不那么美妙了。”
        </p><p>
            众皆莞尔。
        </p><p>
            “再来看看静态类型语言的好处：由于在运行之前进行了类型检查，一方面代码的可靠性增强，符合‘发现错误要尽早’的原则；另一方面编译器有可能藉此优化机器代码以提高运行效率，同时相比前者节省了运行期的耗费在类型检查上的时间和空间。此外，变量类型的声明彰显了编程者的意图，有辅助文档的功效。”冒号一五一十地介绍着，“两种类型的体制可以用两种法律原则来类比：<span class="strong"><strong>静态类型检查类似‘疑罪从有’的有罪推定制</strong></span>——在被证明合法之前是非法的，<span class="strong"><strong>动态类型检查类似‘疑罪从无’的无罪推定制</strong></span>——在被证明非法之前是合法的。至于如何取舍，套用一句话：‘Static Typing Where Possible, Dynamic Typing When Needed’。不妨理解为：<span class="strong"><strong>尽可能守规则，必要时求变通</strong></span>。”
        </p><p>
            句号俏皮地说：“规则如裤带，过于宽松和过于束缚都不好。”
        </p><p>
            问号提出新问题：“动态类型语言与弱类型语言有何不同？”
        </p><p>
            冒号喟言：“它们也常常被混为一谈，但类型的动静与强弱完全是<span class="emphasis"><em>正交</em></span>的两个概念。静态类型语言中，有强类型的Java，也有弱类型的C；动态类型语言中，有强类型的Smalltalk，也有弱类型的JavaScript。前者以类型的<span class="emphasis"><em>绑定（binding）时间</em></span>来划分，后者以类型的<span class="emphasis"><em>约束强度</em></span>来划分。通常<span class="term">弱类型语言</span>（weakly-typed language）允许一种类型的值<span class="emphasis"><em>隐性</em></span>转化为另一种类型<a class="link" href="#note5"><sup>[5]</sup></a>。举个例子，1＋&#8221;2&#8243;在VB中等于3——第二个字符串转化为整数；在JavaScript中等于&#8221;12&#8243;——第一个整数转化为字符串；在C中则等于一个不定的整数值——第二个字符串作为地址来运算。这样似乎很有趣很方便，但程序容易藏污纳垢，滋生臭虫（bug）。与此相对地，<span class="term">强类型语言</span>（strongly-typed language）着意贯彻类型控制，为保障数据的完整性和代码的安全有效性，一般不允许隐性类型转换<a class="link" href="#note6"><sup>[6]</sup></a>。如果一定需要类型转换，必须是显性转换，一般通过我们熟知的<span class="term">铸型</span>（cast）来完成。”
        </p><p>
            引号想起：“好像还有一种所谓的类型安全语言？”
        </p><p>
            逗号紧紧抱着头，仿佛害怕裂开。
        </p><p>
            “类型按<span class="emphasis"><em>安全性</em></span>来划分，可分为<span class="term">类型安全语言</span>（type-safe language）和<span class="term">类型不安全语言</span>（type-unsafe language）。类型检查的目的就是为了避免类型错误（type error）<a class="link" href="#note7"><sup>[7]</sup></a>，即杜绝因类型问题而产生的错误或不良代码。如果一个类型系统能完全做到这一点，它就被称为类型安全的。虽然尚存争议，但一般认为强类型语言对类型控制更严格，因而是类型安全的，弱类型语言是类型不安全的。类型安全固然对保障程序的合理性和可靠性十分重要，但若过于严苛，程序也就失去了活力，正所谓‘水至清则无鱼’啊。” 冒号有条不紊地解说着，“至此，我们已论及数据类型的三种划分方式。需要说明的是，这些划分并非泾渭分明的<a class="link" href="#note8"><sup>[8]</sup></a>，更多的是定性而非定量的描述，甚至没有公认统一的定义。但了解它们，对我们理解编程语言和编程原则是大有裨益的。”
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    Scala是动态语言，却是静态类型的。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    Visual Basic（不包括VB.NET） 支持动态类型，却是静态语言。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    极少数语言没有类型检查（untyped或typeless），如大多数汇编语言、Forth语言等。
                </p></li><li class="listitem"><p><a name="note4"></a>
                    C#4.0将支持duck typing。
                </p></li><li class="listitem"><p><a name="note5"></a>
                    隐式转换也称为强制转换（coercion）。有人将显式转换的铸型（cast）译为强制转换，并不准确。
                </p></li><li class="listitem"><p><a name="note6"></a>
                    但许多强类型语言对于宽转换（widening conversion）还是允许隐性的，如必要时int可自动转换为float。
                </p></li><li class="listitem"><p><a name="note7"></a>
                    典型的类型错误是：一个函数本来期待的参数类型是A，实际传入的变量a却不是A类型或其兼容类型。
                </p></li><li class="listitem"><p><a name="note8"></a>
                    比如，静态类型的OOP语言如C++、Java、C#等支持多态类型以及downcasting，能在运行期间进一步细化数据类型，从某种意义上也具有动态类型的特征。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    尽管动态语言大多数是动态类型语言，但二者并不是一回事。
                </p></li><li class="listitem"><p>
                    数据类型包含两个要素：允许取值的集合和允许参与的运算。
                </p></li><li class="listitem"><p>
                    数据类型既有针对机器的物理意义，又有针对人的逻辑意义，提高了代码的安全性和抽象性。
                </p></li><li class="listitem"><p>
                    动态类型的类型检查发生在运行期间，静态类型的类型检查发生在编译期间（运行之前）。
                </p></li><li class="listitem"><p>
                    动态类型的变量不需要显式声明，静态类型的变量需要通过显式声明或类型推断。
                </p></li><li class="listitem"><p>
                    鸭子类型是动态类型的一种风格，允许非继承性多态，即一个对象的类型可以由其接口集合来确定，不需要通过显式继承。它有利于代码重用，但也可能造成误用和滥用。
                </p></li><li class="listitem"><p>
                    动态类型语言的优点：代码简明灵活、易于重用，适合泛型编程和快速原型开发。
                </p></li><li class="listitem"><p>
                    静态类型语言的优点：运行之前的类型检查增强了代码的可靠性，使编译器有可能进行优化处理从而提高运行效率，节省了运行期的类型检查所占用的时间和空间，同时类型声明有辅助文档的功效。
                </p></li><li class="listitem"><p>
                    静态类型检查实行“疑罪从有”的有罪推定制，动态类型检查实行“疑罪从无”的无罪推定制。取舍的原则是：Static Typing Where Possible， Dynamic Typing When Needed。即尽可能守规则，必要时求变通。
                </p></li><li class="listitem"><p>
                    类型的动静以类型的绑定时间来划分，类型的强弱以类型的约束强度来划分，它们之间没有必然联系。弱类型语言允许类型的隐性转化，被认为是类型不安全的；而强类型语言则一般不允许这种转化，被认为是类型安全的。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Wikipedia．Type system．<a class="link" href="http://en.wikipedia.org/wiki/Type_system" target="_top">http://en.wikipedia.org/wiki/Type_system</a>
                </p></li><li class="listitem"><p>
                    Erik Meijer，Peter Drayton．Static Typing Where Possible, Dynamic Typing When Needed．<a class="link" href="http://research.microsoft.com/~emeijer/Papers/RDL04Meijer.pdf" target="_top">http://research.microsoft.com/~emeijer/Papers/RDL04Meijer.pdf</a>
                </p></li><li class="listitem"><p>
                    Ravi Sethi．Programming Languages: Concepts &amp; Constructs(英文版第2版)．北京：机械工业出版社，2002．136-143
                </p></li></ol></div></div></div><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F23%2Fcolon-class-5_2%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A75.2%EF%BC%9A%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/23/colon-class-5_2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>冒号课堂§5.1：教学计划</title>
		<link>http://blog.zhenghui.org/2009/09/21/colon-class-5_1/</link>
		<comments>http://blog.zhenghui.org/2009/09/21/colon-class-5_1/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 02:39:08 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[程序员]]></category>
		<category><![CDATA[编程范式]]></category>
		<category><![CDATA[迭代学习法]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=440</guid>
		<description><![CDATA[<b>教学计划</b>——接下来的故事（<em>讨论下一步教学计划</em>）<br/>
•	编程水平的提升之道是：在实战中演练招法，在招法中领会心法，心法反过来提升招法，进而提高实战水平，如此循环往复呈螺旋式上升过程。正所谓熟能生巧，巧能生通<br/>
•	迭代学习法：即在具体知识与抽象理论之间进行折返式学习<br/>
•	网页的迷人之处就在于，能够用精美的画皮来包裹冗长低效的代码<br/>
•	无论干哪一行，要想胜任愉快，离不开四样东西：才能、兴趣、方法和努力]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center;"><span style="font-family: 宋体;">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体;">第五课 语言小谈（1）</span></strong>

<p><strong><span style="font-family: 宋体;">课前导读</span></strong></p>
<p style="text-indent: 18pt;"><span style="font-family: 宋体;">本课承上启下，为今后的学习作一些铺垫。在确定教学计划后，对数据类型和动态语言作了简单的介绍，并对有关编程语言的一些观点作出评论。</span></p>
<p style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-family: 宋体;">本课共分四节——</span></p>
<p style="text-indent: 18pt;"><em>1.</em><em><span style="font-family: 宋体;">教学计划——接下来的故事</span></em></p>
<p style="text-indent: 18pt;"><em>2.</em><em><span style="font-family: 宋体;">数据类型——规则与变通</span></em></p>
<p style="margin-left: 18pt;"><em>3.</em><em><span style="font-family: 宋体;">动态语言——穿着彩衣飞舞的脚本语言</span></em></p>
<p style="margin-left: 18pt;"><em>4.</em><em><span style="font-family: 宋体;">语言误区——语言的宗教情结</span></em></p>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="教学计划"><div class="titlepage"><div><div><h1 class="title"><a name="id600625"></a>5.1 教学计划——接下来的故事</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>讨论下一步教学计划</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>褚小者不可以怀大，绠短者不可以汲深</p></div><div class="attribution"><span>—<span class="attribution">《庄子•至乐》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    编程水平的提升之道是：在实战中演练招法，在招法中领会心法，心法反过来提升招法，进而提高实战水平，如此循环往复呈螺旋式上升过程。正所谓熟能生巧，巧能生通
                </p></li><li class="listitem"><p>
                    迭代学习法：即在具体知识与抽象理论之间进行折返式学习
                </p></li><li class="listitem"><p>
                    网页的迷人之处就在于，能够用精美的画皮来包裹冗长低效的代码
                </p></li><li class="listitem"><p>
                    无论干哪一行，要想胜任愉快，离不开四样东西：才能、兴趣、方法和努力
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>什么是迭代学习法？</p></li><li class="listitem"><p>一个合格的程序员需要学习和掌握不同领域的许多知识，如何能胜任愉快？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            新课开始了，冒号一反常态，并没有直奔主题：“在谈论新话题之前，先请诸位畅所欲言，谈谈这段时间的学习感受。”
        </p><p>
            叹号表情有点复杂：“通过前面的学习，让我长了不少见识，只是——”
        </p><p>
            “但讲无妨。” 见叹号有些吞吞吐吐，冒号鼓励道。
        </p><p>
            “只是觉得有点——纸上谈兵。”叹号鼓足勇气说出心里话。
        </p><p>
            引号不以为然：“我倒觉得应该更深入地去了解编程范式，现在有了一些感性认识，但还非常肤浅，希望以后能进一步展开。”
        </p><p>
            逗号挺实在：“有些地方似懂非懂，听起来挺费劲的，直到情景编程才觉得轻松了些。以后可不可以多谈些具体的编程知识、编程技巧和编程经验？”
        </p><p>
            句号拍了拍他的肩膀：“你想学的是招法，老冒传的是心法。”
        </p><p>
            逗号不服：“没有招法再多心法也白搭——光说不练假把式。”
        </p><p>
            句号反驳：“只关注招法，境界永远得不到提升——光练不说傻把式。”
        </p><p>
            “二位请暂停争论。”冒号把头转向问号，“你怎么看？”
        </p><p>
            问号很干脆：“管它心法还是招法，能解决问题的就是好法。”
        </p><p>
            “你倒滑头，整个一白猫黑猫论嘛！”冒号哈哈一笑，“首先，编程范式绝非中看不中用的屠龙之术，它有助于我们更快速地掌握、更深刻地理解、更纯熟地运用编程语言，故有心法之谓。其次，心法只有通过招法才能落到实处，也只有通过招法才能融会贯通。”
        </p><p>
            “那传说中的‘无招胜有招’呢？”引号问。
        </p><p>
            冒号哂道：“武侠小说看多了，容易想入非非，那种境界岂是一般人所能达到的？对绝大多数人来说，无招就意味着自己没招而将中他人之招。”
        </p><p>
            众人窃笑。
        </p><p>
            “还有一样是至关重要的。”冒号提醒道，“那就是实战。”
        </p><p>
            句号深有体会：“以前在学校里编程似乎还得心应手，到了公司就时感力有不逮。”
        </p><p>
            “花拳绣腿对付小喽啰绰绰有余，真碰到高手自然漏洞百出了。”冒号直言道，“编程水平的提升之道是：在实战中演练招法，在招法中领会心法，心法反过来提升招法，进而提高实战水平，如此循环往复呈螺旋式上升过程。正所谓<span class="strong"><strong>熟能生巧，巧能生通</strong></span>。”
        </p><p>
            问号询道：“下面我们的主题是什么？”
        </p><p>
            冒号亮出他的一套学习理论：“软件工程中有个<span class="emphasis"><em>迭代开发法</em></span>，本班则采用<span class="emphasis"><em>迭代学习法</em></span>：即在具体知识与抽象理论之间进行折返式学习。当然这种迭代不是机械式的重复，而是<span class="emphasis"><em>增量式的循环</em></span>。假定你们以前更关注具体的编程语言，那么遵循这种方式，先介绍抽象的编程范式是合适的。在初步了解范式之后，不妨重新回到编程语言上来。”
        </p><p>
            叹号唯唯连声：“是啊，在空中飘久了，会染上恐高症的。”
        </p><p>
            冒号笑着警告：“不要高兴太早，着陆后我们还会再次起飞的——别忘了我们的迭代式学习是周而复始的。至于眼下谈什么，还是先征求各位的意见，这样开放式教学才名副其实嘛。”
        </p><p>
            众人开始交头接耳、七嘴八舌地议论起来。
        </p><p>
            一阵商讨之后，大家似乎未能达成共识。冒号见状，便让他们一一道来。
        </p><p>
            问号再次充当急先锋：“能不能比较一些当今主流语言各自的优缺点？”
        </p><p>
            冒号笑言：“我怎么恍惚间又回到了第一堂课？你的潜台词还是那句话：到底学哪种语言好？”
        </p><p>
            问号被窥破心事，微露窘色。
        </p><p>
            “不过我非常理解你们的想法。”冒号体谅道，“虽然这是编程中最易提出却又最难回答的问题，但考虑到大家对它如此兴致盎然，我决定不顾引火烧身之危，铤而走险一回。”
        </p><p>
            众人鼓掌。
        </p><p>
            冒号故作疑惑：“你们这是对问题的答案表示期待呢，还是对我的勇气表示赞赏？”
        </p><p>
            众皆笑曰：“兼而有之，兼而有之！”
        </p><p>
            叹号提出：“近来动态语言非常流行，能说说它与静态语言到底有何不同，是否会取而代之？”
        </p><p>
            “嗯，这个问题总算简单了些。”冒号如释重负。
        </p><p>
            逗号坚持道：“我还是那个建议，希望学些具体的编程知识和技巧，比如将最流行的Java语言中的一些重点和难点分几个专题来讨论。”
        </p><p>
            冒号颔许：“这是个很好的建议，可以采纳。”
        </p><p>
            引号有不同意见：“Java没有C++来劲：要说难点，C++多得多；要说流行度，按照TIOBE的数据，C与C++之和还超过Java六个百分点呢。”
        </p><p>
            逗号不服：“你没看到C和C++正在逐渐没落吗？”
        </p><p>
            引号冷哼一声：“开玩笑，什么时候操作系统、数据库、游戏软件和嵌入式系统都改用Java了再说这话。别忘了，Java的虚拟机都还是C或C++写成的呢。”
        </p><p>
            冒号忙止住干戈：“我还没来得及成为众矢之的呢，你们二位倒先掐上了。”
        </p><p>
            句号提议：“最好找一个项目实例，从头至尾演练一次，既能贯穿各个知识点，又能让我们对软件开发有个整体认识。”
        </p><p>
            “这个想法听起来非常不错。”冒号沉吟了一会又道，“只是一个真正企业级的项目，涉及面太广。比如一个完整的web应用，不论是采用重量级的Java EE或.NET技术，还是采用轻量级的Perl、PHP、Ruby、Python等动态语言技术，除了要掌握各自的主体语言外，还涉及到相应的框架、集成环境和各种工具，以及JavaScript、CSS、HTML和XML等技术，同时数据库的知识也是不可或缺的。”
        </p><p>
            问号奇道：“JavaScript、CSS和HTML这些不主要是网页设计人员的语言吗？”
        </p><p>
            冒号解释：“网页设计人员大多用Dreamweaver之类的工具来设计HTML页面，开发一般网站尚可勉力而为，若开发企业级软件则有些力不从心了。更何况web应用的趋势是具有更丰富用户体验的Rich Internet application （RIA），采用大量的AJAX、FLEX等技术，需要熟悉Javascript或Actionscript之类的语言，这些就更非一般网页设计人员所能胜任。”
        </p><p>
            引号插言：“据我所知，许多公司都是请网页设计师来编写HTML和Javascript等代码的。”
        </p><p>
            冒号指出：“网页的迷人之处就在于，能够用精美的画皮来包裹冗长低效的代码。出于软件开发的时间和成本的考虑，公司的选择无可非议，但如果要提高软件竞争力，这些代码至少要经过程序员的加工处理。”
        </p><p>
            逗号复言：“那数据库总该是数据库管理员的事吧？程序员至多用到hibernate、iBATIS之类的ORM<a class="link" href="#note1"><sup>[1]</sup></a>框架。”
        </p><p>
            冒号断然否定：“数据库绝不只是DBA的事，ORM也不能取代数据库的设计和SQL的使用。另外，复杂的应用需要编写大量的<span class="term">存储过程</span>（stored procedure），故还应掌握PL/SQL或Transact-SQL等扩展数据库语言。换句话说，从web开发最前端的网页到最后端的数据库，都应该有程序员的身影。”
        </p><p>
            句号联想到：“借用前面餐馆的例子，不妨把接待员看作<span class="term">客户层</span>（client tier），把服务员看作<span class="term">表现层</span>（presentation tier），把厨师看作<span class="term">业务层</span>（business tier），把收银员看作<span class="term">数据层</span>（data tier），把厨工看作常用的<span class="term">辅助类</span>（helper class）<a class="link" href="#note2"><sup>[2]</sup></a>。”
        </p><p>
            冒号微微点头：“比较靠谱。要说不当之处，就是服务器端的表现层不会如服务员那样直接与客户打交道，此外业务层常与数据层打交道，但厨师好像不会与收银员有什么瓜葛。”
        </p><p>
            叹号夸张地捂住脸：“天哪，程序员竟然身兼五职，太惨了吧？”
        </p><p>
            “当然程序员会各有分工，不过如果你总局限某一层的应用开发，今后凭什么谋取更高的职位？”冒号苦口婆心，“<span class="strong"><strong>无论干哪一行，要想胜任愉快，离不开四样东西：才能、兴趣、方法和努力。没有才能则难以胜任；没有兴趣则难以愉快；没有方法则事倍功半；没有努力则一事无成</strong></span>。我相信好的方法最终能激发人的才能、兴趣和努力，这也是本班的一个理念。希望大家能通过各种问题的讨论，获得一些方法上的启示。”
        </p><p>
            问号急切地询问：“那么我们的下一步是什么？”
        </p><p>
            “综合各位的意见，我们从简到繁。”冒号公布计划，“先简单谈谈动态语言；再对主流语言作简评；然后范式上以OOP为主，语言上以C++、Java和C#为主，作一些专题讨论；最后如果时间允许，找一个项目来实践一番。”
        </p><p>
            “呕耶！”众人皆大欢喜。
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    ORM（Object-Relational Mapping）是一种编程技术，能将OOP中的对象模型映射到数据库的关系模型。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    传统的三层架构为：表现层、业务层和数据层。其中表现层可进一步分为客户端的客户层和服务器端的表现层，数据层有时用集成层（integration tier）和资源层（resource tier）代替。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    所谓迭代学习法，是指在具体知识与抽象理论之间进行增量式的循环学习。
                </p></li><li class="listitem"><p>
                    一个合格的程序员不应只局限某一层的应用开发。
                </p></li><li class="listitem"><p>
                    要想工作胜任愉快，才能、兴趣、方法和努力缺一不可。一套好的方法可以激发才能、兴趣和努力。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Deepak Alur，John Crupi，Dan Malks．Core J2EE Patterns: Best Practices and Design Strategies．Upper Saddle River, NJ：Prentice Hall PTR，2003．120-121
                </p></li></ol></div></div></div><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F21%2Fcolon-class-5_1%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A75.1%EF%BC%9A%E6%95%99%E5%AD%A6%E8%AE%A1%E5%88%92">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/21/colon-class-5_1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
