<?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>冒号空间 &#187; 过程式编程</title>
	<atom:link href="http://blog.zhenghui.org/tag/procedural-programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.zhenghui.org</link>
	<description>自然、人类、机器</description>
	<lastBuildDate>Fri, 30 Dec 2011 03:14:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>冒号课堂§2.4：并发范式</title>
		<link>http://blog.zhenghui.org/2009/09/07/colon-class-2_4/</link>
		<comments>http://blog.zhenghui.org/2009/09/07/colon-class-2_4/#comments</comments>
		<pubDate>Mon, 07 Sep 2009 05:14:57 +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>
		<category><![CDATA[逻辑式编程]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=361</guid>
		<description><![CDATA[<b>并发范式</b>——合作与竞争（<em>并发式编程简谈</em>）<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="id599705"></a>2.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></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></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>（concurrent programming）就是其中之一。”
        </p><p>
            叹号有些惊讶：“并发式编程也算一种范式？它似乎更像是提高运行效率的一种手段。” 
        </p><p>
            “大谬不然。”冒号摇摇头，“真正的并发式编程，绝不只是调用线程<a class="link" href="#note1"><sup>[1]</sup></a>API或使用synchronized、lock之类的关键字那么简单。从宏观的架构设计，到微观的数据结构、流程控制乃至算法，相比通常的串行式编程都可能发生变化。随着硬件性能和用户需求的双重提升，并发式编程已成为不可回避的主题。毫不夸张地说，并发式编程是继OOP之后又一场思想和技术上的革命。只是相比OOP，尽管年龄相仿，但语言上不够支持，标准上不够统一，理论上不够完善，因而这场革命更具<span class="emphasis"><em>破坏性</em></span>和<span class="emphasis"><em>建设性</em></span>。现在我们来看一个例子，比较两种烧水泡茶的方案。”
        </p><p>
            说着冒号在黑板上写下——
        </p><div class="informalexample"><p>方案一：洗茶杯；放茶叶；灌水壶；烧水；水开后泡茶。</p><p>方案二：灌水壶；在烧水的同时，洗茶杯；放茶叶；水开后泡茶。</p></div><p>
            引号见多识广：“我记得这好像是运筹学中的例子，显然方案二更佳。从编程的角度来看，方案一是串行式编程，方案二是并发式编程——烧水的线程与洗茶杯放茶叶的线程是同时进行的。”
        </p><p>
            “如果方案一也用并发式编程呢？”冒号追问。
        </p><p>
            引号一愣，随即道：“必须先洗茶杯后放茶叶，洗茶杯放茶叶的同时也没法烧水，至于泡茶，更得等水开之后了。”
        </p><p>
            句号明白了冒号的用意：“这就是说，单凭并发式编程并不能保证提高程序性能，还必须在程序设计上下功夫。” 
        </p><p>
            问号继续深究：“即便如此，如果硬件不支持，并发式编程也未必能提高效率啊。比如在一台单处理器的主机上，多个线程只能是模拟的、逻辑上的并行，而非真正物理上的并行。”
        </p><p>
            “这话有一定道理。”冒号有限度地表示赞同，“但设计者应该未雨绸缪，总不能等到有了多处理器才想到并发式编程吧？再者，没有多处理器，是不是可以利用多台单处理器的主机同时运算呢？退一步讲，即使在一台单处理器的情况下，并发式编程有时也是必不可少的。它能保证不同用户、不同程序之间的公平竞争，这对多用户、多任务的系统而言尤为重要。此外，采用并发式编程同样可能提高性能。最典型的一个例子：当一个线程因为等待某种资源而被堵塞时，可以切换到其他线程而不至让CPU闲置。更重要的一点是，难道除了缩短程序运行时间外，并发式编程就没有别的好处吗？譬如打开一个网页，你是希望浏览器边下载边显示网页呢，还是下载完成后再显示？”
        </p><p>
            “当然是边下载边显示啦。” 叹号毫不犹豫地说，“如果每个网页都是下载完成后再显示，那还不把人给憋坏了！”
        </p><p>
            逗号加了一句：“浏览器加载文字和加载图像也应分开在不同的线程，如果用户对文字部分不感兴趣，不等图像显示就可直接关闭网页了。”
        </p><p>
            “如果网页被提前关闭，那也是假用户之手变相缩短了程序运行时间。”冒号接过话来，“还有一个常见的例子，包括浏览器在内的许多应用软件在运行中都会显示一个进程条。该进程条的更新需要一个单独的线程，从效率上看它起的作用是负面的，但大大提高了用户体验，是软件人性化的表现。再举一例，媒体播放器一般都会提供暂停、快进、倒退、快放、慢放等按钮，如果不采用多线程，它们将形同虚设。此处并发式编程的作用在于提高了软件的响应能力，也改善了用户体验——有谁愿意驾驶一辆启动后不能刹车、不能倒车、不能变速、油尽方停的汽车呢？”
        </p><p>
            “岂止是不愿意，简直是恐怖！”叹号加重了语气。
        </p><p>
            “对于操作系统、各种实时系统和诸如数据库、网络服务器等基于服务的系统来说，在响应用户请求的时间上和资源的合理分配上有着极高的要求，并发式编程更是不可或缺。”句号接着补充。
        </p><p>
            问号紧接着又问：“并发式编程还有其他用处吗？”
        </p><p>
            冒号应道：“不同编程范式采用不同的视角和方法来设计和开发软件。并发式编程<span class="emphasis"><em>以进程为导向</em></span>（Process-Oriented）、以任务为中心将系统模块化。我们都知道，模块化在编程中是个好东西。”
        </p><p>
            引号心存疑惑：“过程式中引入了函数模块，对象式中引入了对象模块，但并发式似乎没有<span class="emphasis"><em>在语法上</em></span>引入新型模块，比如C和Java中的线程其实不过是函数或方法的包装而已。”
        </p><p>
            “我猜你的意思是：在定义一个线程之前，其主函数已经模块化了，不能把功劳记在并发式编程上，对吧？”冒号笑问，“你不能孤立静止地看待每个模块，还要考虑到模块之间的相互关联和作用。相比串行式，并发式在模块之间引入了新的通讯和控制方式。也就是说，原先的一些模块的定义和划分一定是建立在线程机制的基础上的。如果失去线程的支持，它们的合理性自然会打上问号，说不定整体设计都会受到牵连。这也体现了编程范式的<span class="emphasis"><em>渗透性和全局影响力</em></span>。”
        </p><p>
            教室上空弥漫的疑云一消而散。
        </p><p>
            冒号进一步指出：“除了用户主观上的需求和硬件客观上的可能外，并发式显得格外重要的另一深层原因是：许多程序是现实世界的模拟，而我们生活的世界不折不扣是并发式的。从某种意义上看，并发式的模拟比对象式的模拟更贴近世界。”
        </p><p>
            引号再次提问：“并发式编程在设计上有什么要求？”
        </p><p>
            “并发式编程<span class="strong"><strong>以资源共享与竞争为主线</strong></span>——又是对当今世界形势的一个逼真模拟。这意味着程序设计将围绕进程的划分与调度、进程之间的通讯与同步<a class="link" href="#note2"><sup>[2]</sup></a>等等来展开。合理的并发式设计需要诸多方面的权衡考量。”冒号说着，放出一段幻灯片——
        </p><div class="informalexample"><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>软件易于重用、维护、测试</p></li><li class="listitem"><p>公平有效地利用资源，优化程序性能如增大吞吐量、减少响应时间、提高效率等</p></li><li class="listitem"><p>保障进程安全，防止<span class="term">竞态条件</span>（race condition）</p></li><li class="listitem"><p>保持进程活性，避免死锁、饥饿、活锁、资源枯竭等</p></li><li class="listitem"><p>减少锁开销、上下文切换等带来的性能损失</p></li><li class="listitem"><p>妥善处理多进程在算法、调试等方面带来的复杂性</p></li></ul></div></div><p>
            叹号蹙眉：“并发式编程好是好，就是太复杂。”
        </p><p>
            “天下没有免费的午餐。有所得，必有所失。” 冒号淡淡地说，“并发式编程当然不容易，但也并非难以掌握。最重要的是，作为一个程序员，你不得不面对它。即使你不直接用并发式编程，你依赖的代码和依赖你的代码也可能用到；即使现在没有用并发式，将来也可能用到。如果采取避而不理的鸵鸟政策，早晚会被人点中你的死穴。虽然目前不会对并发式编程作更深入的探讨，但希望能引起你们足够的重视。”
        </p><p>
            句号谈及他的感受：“相比OOP在语言上得到的支持，并发式的支持力度好像很不够。”
        </p><p>
            冒号点头称是：“这是由并发式的复杂性和成熟度决定的。另外，在究竟是在语言级别上支持并发、还是交由操作系统处理的问题上，仁者见仁，智者见智。Ada、Java和C#等选择前者，在语法上对并发式编程有一定的支持；C和C++等选择后者，除了关键字volatile外，主要靠库函数支持。专门为并发式而设计的语言大多仅限于学术研究而非商业应用，Erlang语言<a class="link" href="#note3"><sup>[3]</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>为主题，一个以<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="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><div class="informalexample"><p>过程式：以过程为模块的君主体系，模块之间互相授命与听命</p><p>函数式：以函数为模块的数学体系，模块之间互相替换与合成</p><p>逻辑式：以断言为模块的逻辑体系，模块之间互相归纳与演绎</p><p>对象式：以对象为模块的民主体系，模块之间互相交流与服务</p><p>并发式：以进程为模块的生产体系，模块之间互相竞争与合作</p></div><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>
                    并发式编程中以进程（process）或线程（thread）为基本单位。尽管它们有很大的差异，但为简明起见，这里不加区分地交替使用两个术语。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    <span class="term">同步</span>（synchronization）只在采用<span class="term">共享内存</span>（shared memory）的并发模型中需要，在采用<span class="term">消息传递</span>（message passing）的并发模型中并不需要。本文主要以前一种并发模型为讨论对象，它也是大多数语言或库（包括C、C++、Java、C#等）所支持的模型。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    Erlang是由爱立信开发的一种通用编程语言，支持函数式和并发式，采用消息传递的并发模型。
                </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"><div class="table"><a name="id640460"></a><p class="title">五大重要范式对比：</p><div class="table-contents"><table summary="五大重要范式对比" border="1"><colgroup><col><col><col><col></colgroup><thead><tr><th>范式</th><th>体系</th><th>模块</th><th>模块关系</th></tr></thead><tbody><tr><td>过程式</td><td>君主体系</td><td>过程</td><td>授命与听命</td></tr><tr><td>函数式</td><td>数学体系</td><td>函数</td><td>替换与合成</td></tr><tr><td>逻辑式</td><td>逻辑体系</td><td>断言</td><td>归纳与演绎</td></tr><tr><td>对象式</td><td>民主体系</td><td>对象</td><td>交流与服务</td></tr><tr><td>并发式</td><td>生产体系</td><td>进程</td><td>竞争与合作</td></tr></tbody></table></div></div><br class="table-break"></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>
                    Abraham Silberschatz，Peter Galvin．Operating System Concepts，5ed.．Reading, MA：Addison-Wesley，1998．155-235
                </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>02-01 在你所掌握的语言当中，有哪些是命令式的？哪些是声明式的？其中，命令式语言里有哪些声明式的特征？声明式的语言里有哪些命令式的特征？它们各自有哪些优点和缺点？</li>
    <li>02-02 你编写的程序符合结构化编程的原则吗？</li>
    <li>02-03 你接触过函数式语言和逻辑式语言吗？如果没有，试着阅读相关的入门书籍，体会它们与过程式迥然不同的风味。（函数式语言推荐Haskell和 Scheme，逻辑式语言推荐Prolog）</li>
    <li>02-04 相比纯过程式的编程语言（如C语言），你认为OOP语言主要有哪些优势？又有哪些劣势？</li>
    <li>02-05 你认为在并发式编程设计中，最重要的是什么？最困难的是什么？</li>
</ul><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F07%2Fcolon-class-2_4%2F&amp;title=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A72.4%EF%BC%9A%E5%B9%B6%E5%8F%91%E8%8C%83%E5%BC%8F" id="wpa2a_2">分享/保存</a></p><h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2009年09月4日 -- <a href="http://blog.zhenghui.org/2009/09/04/colon-class-2_2/" title="冒号课堂§2.2：声明范式">冒号课堂§2.2：声明范式</a> (1)</li><li>2009年09月15日 -- <a href="http://blog.zhenghui.org/2009/09/15/colon-class-4_2/" title="冒号课堂§4.2：逻辑范式">冒号课堂§4.2：逻辑范式</a> (0)</li><li>2009年09月13日 -- <a href="http://blog.zhenghui.org/2009/09/13/colon-class-4_1/" title="冒号课堂§4.1：函数范式">冒号课堂§4.1：函数范式</a> (0)</li><li>2009年09月6日 -- <a href="http://blog.zhenghui.org/2009/09/06/colon-class-2_3/" title="冒号课堂§2.3：对象范式">冒号课堂§2.3：对象范式</a> (3)</li><li>2009年09月21日 -- <a href="http://blog.zhenghui.org/2009/09/21/colon-class-5_1/" title="冒号课堂§5.1：教学计划">冒号课堂§5.1：教学计划</a> (1)</li><li>2009年09月19日 -- <a href="http://blog.zhenghui.org/2009/09/19/colon-class-4_4/" title="冒号课堂§4.4：情景范式">冒号课堂§4.4：情景范式</a> (0)</li><li>2009年09月17日 -- <a href="http://blog.zhenghui.org/2009/09/17/colon-class-4_3/" title="冒号课堂§4.3：汇总范式">冒号课堂§4.3：汇总范式</a> (5)</li><li>2009年09月11日 -- <a href="http://blog.zhenghui.org/2009/09/11/colon-class-3_4/" title="冒号课堂§3.4：事件驱动">冒号课堂§3.4：事件驱动</a> (2)</li><li>2009年09月10日 -- <a href="http://blog.zhenghui.org/2009/09/10/colon-class-3_3/" title="冒号课堂§3.3：切面范式">冒号课堂§3.3：切面范式</a> (4)</li><li>2009年09月9日 -- <a href="http://blog.zhenghui.org/2009/09/09/colon-class-3_2/" title="冒号课堂§3.2：超级范式">冒号课堂§3.2：超级范式</a> (2)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/07/colon-class-2_4/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>冒号课堂§2.3：对象范式</title>
		<link>http://blog.zhenghui.org/2009/09/06/colon-class-2_3/</link>
		<comments>http://blog.zhenghui.org/2009/09/06/colon-class-2_3/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 17:26:50 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[易用性]]></category>
		<category><![CDATA[编程范式]]></category>
		<category><![CDATA[过程式编程]]></category>
		<category><![CDATA[重用性]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=353</guid>
		<description><![CDATA[<b>对象范式</b>——民主制社会的编程法则（<em>对象式编程简谈</em>）<br/> • 如果把整个流程看作一颗倒长的大树，过程式编程自树根向下，逐渐分支，直到每片树叶，类似数学证明中的分析法，即执果索因的逆推法；OOP则从每片树叶开始，逐渐合并，直到树根，类似数学证明中的综合法，即执因索果的正推法<br/> • 与其说OOP更具重用性，不如说更具易用性<br/> • 函数是被动的实体，对象是主动的实体<br/> • 过程式程序的世界是君主制的；OO程序的世界是民主制的<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="id622049"></a>2.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>
                    如果把整个流程看作一颗倒长的大树，过程式编程自树根向下，逐渐分支，直到每片树叶，类似数学证明中的分析法，即执果索因的逆推法；OOP则从每片树叶开始，逐渐合并，直到树根，类似数学证明中的综合法，即执因索果的正推法
                </p></li><li class="listitem"><p>
                    与其说OOP更具重用性，不如说更具易用性
                </p></li><li class="listitem"><p>
                    函数是被动的实体，对象是主动的实体
                </p></li><li class="listitem"><p>
                    过程式程序的世界是君主制的；OO程序的世界是民主制的
                </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>OOP是一种特殊的命令式吗？</p></li><li class="listitem"><p>OOP的基本思想是什么？</p></li><li class="listitem"><p>OOP到底好在哪里？</p></li><li class="listitem"><p>OOP将要一统天下吗？</p></li><li class="listitem"><p>过程式编程与OOP在设计理念上有什么差异？</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>
            “面向对象？”冒号咕哝着，“姑且称之为OO或对象式吧，既不标新立异，也不以讹传讹。在回答你的问题之前，请先回答我的：什么是OOP？”
        </p><p>
            引号应答如流：“<span class="term">OOP</span>（Object-Oriented programming）是一种计算机编程模式，它以对象作为问题空间的基本元素，利用对象和对象间的相互作用来设计程序。所谓对象，是实际问题中实体的抽象，具有一定的属性和功能。OOP的三个基本特征是：封装性、继承性和多态性。所谓封装性就是——”
        </p><p>
            冒号作了个暂停的手势：“OOP的的基本特征相信大家早就耳熟能详了，那么根据你刚才的定义，能否得出OOP一定是命令式的结论？”
        </p><p>
            引号歪头想了一阵，答道：“从定义上好像并不能得出，难道C++、Java、C#不是命令式的吗？”
        </p><p>
            冒号回答：“当然是，但这不妨碍Clos成为OO版的Lisp，而Prolog也有不少融入OO特征的扩充，如Visual Prolog、Logtalk等。OOP虽然是在命令式的基础上发展起来的，但其核心思想可泛化为：以数据为中心组织逻辑，将系统视为相互作用的对象集合，并利用继承与多态来增强可维护性、可扩展性和可重用性。这种思想也能应用到函数式和逻辑式中，只不过对象的方法从命令式中的过程分别换成函数式中的函数和逻辑式中的断言罢了。大致说来，命令式、函数式和逻辑式互相平行，而OOP与它们正交。”
        </p><p>
            问号提问：“OOP已经成为一种潮流，上堂课列举的十二种流行语言中只有C不是OO的，这是否意味着OOP将要一统天下？”
        </p><p>
            “严格说来，VB（VB.NET除外）和JavaScript也不是OO的，只是<span class="term">基于对象的</span>（Object Based）<a class="link" href="#note1"><sup>[1]</sup></a>。” 冒号纠正道，“至于OOP是否会一统天下，答案是否定的。首先，与能独当一面的三类最基本的范式不同，纯粹的OOP是不存在的<a class="link" href="#note2"><sup>[2]</sup></a>，必须结合其他范式；其次，世上没有包治百病的万灵丹方，OOP也不例外。用软件业的行话来说：没有银弹（No silver bullet）<a class="link" href="#note3"><sup>[3]</sup></a>。OOP最适用于大型复杂的、交互式的、尤其是与现实世界密切相关的系统，但在小型应用、数学计算、符号处理等方面并无优势。需要指出的是，语言和范式的流行，与大公司支持和商业推动是密切相关的。有人说OOP其实是MOP（Money-Oriented Programming），即以金钱为导向的。虽有过激之嫌，但有经验的股民都知道，有主力运作的股票总是涨得快一些的。当然OOP能流行，自有独到之处，谁能说说它到底好在哪里？”
        </p><p>
            逗号抢答：“OOP能提高软件的可维护性、可扩展性和可重用性。”
        </p><p>
            冒号反问：“为什么过程式编程的可维护性、可扩展性和可重用性就差呢？”
        </p><p>
            感到来者不善，逗号有点发虚：“因为OOP具有信息隐藏、继承和多态的特征。”
        </p><p>
            冒号并不买帐：“首先，将可维护性、可扩展性和可重用性与OOP划等号，是只见树木，不见森林——那是所有范式和语言的共同目标。其次，以C语言为例，信息隐藏可用关键字static来实现；继承可用<span class="term">合成</span>（composition）来代替；多态可以利用函数指针来实现。更何况这些只是手段而非目的，只要设计合理，C程序同样具有可维护性、可扩展性和可重用性，性能效率还更优越。即使在OOP日益风行的今天，C的占有率始终稳踞前列，许多大型复杂软件如操作系统、数据库等仍以C为主，这足以证明其仍堪大用。”
        </p><p>
            见逗号有些理屈词穷，冒号语气放缓：“请不要误解，我并非OOP的反对者，相反今后还要重点讨论它。但我希望大家少一点照本宣科和人云亦云，多一点独立思考，甚至不妨标新立异。”
        </p><p>
            稍作停顿，冒号继续发问：“过程式编程与OOP在设计理念上有什么区别？”
        </p><p>
             “过程式编程的理念是以过程为中心，自顶向下、逐步求精<a class="link" href="#note4"><sup>[4]</sup></a>。”引号一出口就自感有些“照本宣科”，见冒号正用鼓励的目光看着他，这才继续说下去，“OOP则正相反，以数据为中心，自底向上、逐步合并。”
        </p><p>
            冒号首肯道：“如果把整个流程看作一颗倒长的大树，过程式编程自树根向下，逐渐分支，直到每片树叶，类似数学证明中的分析法，即<span class="emphasis"><em>执果索因</em></span>的逆推法；OOP则从每片树叶开始，逐渐合并，直到树根，类似数学证明中的综合法，即<span class="emphasis"><em>执因索果</em></span>的正推法。”
        </p><p>
            句号心领神会：“倘若把树根看成主函数，离树根越近，离用户需求也越近。如果用过程式编程，由于是逆推法，树干改变容易导致树枝相应改变，因此一旦用户需求发生变化，可能会从树根波及到树枝甚至树叶，维护起来殊为不易。相反OOP从树叶开始设计，离用户需求较远，抽象程度较高，受波及的程度较小，因此更易维护和重用。”
        </p><p>
            冒号拊掌赞道：“好极了！”
        </p><p>
            问号不解：“您刚才不还说C程序同样具有可重用性吗？”
        </p><p>
            冒号微微一笑：“数学中分析法与综合法往往是结合起来使用的，过程式编程与OOP也是如此，只不过各有偏重罢了。句号的一番话虽不无道理，但也授OOP的反对者以口实：OOP鼓吹的可重用性来自‘自底向上’的设计模式，而这种模式并非OOP的专利。其实软件设计的最重要的并不是编程语言，甚至也不是编程范式，而是<span class="strong"><strong>抽象思维</strong></span>。关于这一点，我们今后还会详细阐述。”
        </p><p>
            叹号不甘寂寞，插言道：“OOP以对象为基本模块单位，而对象是现实中具体事物和抽象概念的模拟，这使得编程设计更自然更人性化。”
        </p><p>
            “深合吾意！”冒号挥动着右手，“尽管OOP最大的卖点是其高度的可重用性，相比其他范式却并不具明显优势。但它更接近人类的认知模式，编程者更容易也更乐于用这种方式编程，这是它深入人心的一个重要原因。比较一下两种用法：<code class="code">牛.吃（草）</code>与<code class="code">吃（牛，草）</code>，哪种更接近人类思维？”
        </p><p>
            有人在底下嘀咕：“如果把牛换成狗，那么一个是狗吃屎，一个是吃狗屎。”
        </p><p>
            全班捧腹。
        </p><p>
            冒号也忍不住笑了：“OOP人性化的另一表现是其接口简洁易记。看看Win32 API、Unix API等之类操作系统接口或OCI之类的数据库接口，函数的参数动辄七八个乃至上十个，函数名和数据结构成员也多冗长晦涩，既难记又易错。相比之下，相应的Java的API显然平易近人得多。”
        </p><p>
            问号刨根问底：“为什么C的API不能象Java的那么简洁呢？”
        </p><p>
            冒号释疑：“单纯这么比较其实对C并不公平，因为Java的API虽然简洁易用，但功能上与相应C的API并不等同，换句话说，Java把<span class="emphasis"><em>接口粗粒度化</em></span>了。”
        </p><p>
             “接口粗粒度化？”引号质疑道，“就是把一些函数包装起来吧？我们也可以用C将操作系统、数据库之类的API再包装一下。”
        </p><p>
            “事实上许多软件公司都曾这样做过。”冒号颔首作答，“但C函数不像Java对象，本身没有状态，只有依靠参数传递或外部变量来维持相关函数之间的联系，包装后的接口肯定不如Java简洁，但应该比Java高效。说白了，OOP就是将相关的函数用数据粘合，重新包装后再贴上对象的标签。从这种角度上看，<span class="strong"><strong>与其说OOP更具重用性，不如说更具易用性</strong></span>。”
        </p><p>
            叹号狐疑道：“OOP并不更具重用性？这可是它的金字招牌啊！”
        </p><p>
            冒号冷哼一声：“不要被金字招牌晃晕了眼，我来问你：是收音机、电视机之类的电器产品更具重用性呢，还是电阻、电容之类的电器元件更具重用性？”
        </p><p>
             “当然是电器元件啦。”叹号冲口而出。
        </p><p>
            冒号因势利导：“每个电器元件具备单一的功能，正如过程式中的函数；每个电器产品是对多个相互关联的电器元件的封装，正如OOP中的对象。同样的电器元件可用于不同的电器产品，具有高度的可重用性，而电器产品重用性低，但易用性高。<a class="link" href="#note5"><sup>[5]</sup></a>”
        </p><p>
            众人犹自将信将疑。
        </p><p>
            “对一个没有独立思考习惯的人来讲，与其说他认同一个理论，倒不如说他认同该理论倡导者的权威。而在他仰视权威的同时，也把自己的思想交托给了权威。”冒号颇具犬儒之风，“你们可以怀疑我的观点，但绝不可放弃自己的思考。请注意，这就是我在第一堂课提到的精神——<span class="strong"><strong>批判精神</strong></span>。”
        </p><p>
            冒号这时停了下来，与在座的每位逐一对视。他仿佛想通过目光把这种精神注入到每个人的身上，就像武侠小说中通过手掌将内功传输给他人一样。并不是每个人都能理解冒号的用心，但都或多或少地感受到一种异样的气氛。
        </p><p>
            “关于OOP今天就谈到这里。”冒号恢复了常态，“请不要奇怪为何如此流行的编程范式我却一带而过，那是因为你们对它相对比较熟悉，而我们这一轮只是在作热身运动，以后再作专项训练。在结束之前，我们引进一个新视点：过程式编程的模块以函数为单位，OOP的模块以对象为单位，二者的区别是：函数是被动的实体，对象是主动的实体。<span class="strong"><strong>过程式程序的世界是君主制的</strong></span>，主函数是国王，其他函数是臣民，等级分明，所有臣民在听命于上级的同时也对下级发号施令，最终为国王服务；<span class="strong"><strong>OO程序的世界是民主制的</strong></span>，所有对象都是独立而平等的公民，有权利保护自己的财产和隐私并向他人寻求服务，同时有义务为他人提供承诺的服务，公民之间通过信息交流来协作完成各种任务。更进一步地，<span class="strong"><strong>封装使得公民拥有个体身份</strong></span>，需要对自己负责；<span class="strong"><strong>继承使得公民拥有家庭身份</strong></span>，需要对家庭负责；<span class="strong"><strong>多态使得公民拥有社会身份</strong></span>，需要对社会负责。欲知个中玄机，且听我日后慢慢道来。”
        </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>
                    所谓基于对象的，有两种不同的涵义。一种指“限制版”的OOP，即具备对象概念，但不具备OOP的一些其他特征，如继承或多态等。Visual Basic（不包括Visual Basic .NET）正属于此类。另一种指基于原型的（prototype-based），或者说基于实例的（instance-based），而不像通常OOP是基于类的（class-based）。JavaScript、NewtonScript、MOO等语言即属此类。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    这里所谓“纯粹的OOP”并非指一般意义上的“pure OOP”（即所谓的“一切都是对象”），而指单纯的、不含其他范式的OOP。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    出自Fred Brooks的著名文章《no silver bullet》（参见文献【2】）。他认为没有一项技术或管理方法的发展能保证，在十年内让软件的生产力、可靠性或简洁性等方面提高一个数量级。常用来泛指没有一项软件技术或方法是万能的。
                </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 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>
                    OOP大多是命令式的，但也有函数式的和逻辑式的OO语言。
                </p></li><li class="listitem"><p>
                    OOP的核心思想可以归纳为：以数据为中心组织逻辑，将系统视为相互作用的对象集合，并利用继承与多态来增强可维护性、可扩展性和可重用性。
                </p></li><li class="listitem"><p>
                    OOP既不能脱离其他范式，也绝非适用于一切应用。
                </p></li><li class="listitem"><p>
                    可维护性、可扩展性和可重用性是所有范式和语言的共同目标，并非OOP所独有。
                </p></li><li class="listitem"><p>
                    与其说OOP更具重用性，不如说更具易用性。
                </p></li><li class="listitem"><p>
                    过程式编程以过程为中心，自顶向下，逐步求精。
                </p></li><li class="listitem"><p>
                    对象式编程以数据为中心，自底向上，逐步合并。
                </p></li><li class="listitem"><p>
                    过程式程序的世界是君主制的，OO程序的世界是民主制的。
                </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．Object-oriented programming．<a class="link" href="http://en.wikipedia.org/wiki/Object-oriented_programming" target="_top">http://en.wikipedia.org/wiki/Object-oriented_programming</a>
                </p></li><li class="listitem"><p>
                    Frederick Brooks．The Mythical Man-month．Boston：AddisonWesley，1995．179-203
                </p></li></ol></div></div></div><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F06%2Fcolon-class-2_3%2F&amp;title=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A72.3%EF%BC%9A%E5%AF%B9%E8%B1%A1%E8%8C%83%E5%BC%8F" id="wpa2a_4">分享/保存</a></p><h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2009年09月10日 -- <a href="http://blog.zhenghui.org/2009/09/10/colon-class-3_3/" title="冒号课堂§3.3：切面范式">冒号课堂§3.3：切面范式</a> (4)</li><li>2009年09月7日 -- <a href="http://blog.zhenghui.org/2009/09/07/colon-class-2_4/" title="冒号课堂§2.4：并发范式">冒号课堂§2.4：并发范式</a> (2)</li><li>2009年08月21日 -- <a href="http://blog.zhenghui.org/2009/08/21/contents-of-colonclass/" title="《冒号课堂》目录">《冒号课堂》目录</a> (29)</li><li>2011年04月18日 -- <a href="http://blog.zhenghui.org/2011/04/18/more-words-on-abstraction/" title="答读者问(3)——再谈抽象">答读者问(3)——再谈抽象</a> (1)</li><li>2009年09月21日 -- <a href="http://blog.zhenghui.org/2009/09/21/colon-class-5_1/" title="冒号课堂§5.1：教学计划">冒号课堂§5.1：教学计划</a> (1)</li><li>2009年09月19日 -- <a href="http://blog.zhenghui.org/2009/09/19/colon-class-4_4/" title="冒号课堂§4.4：情景范式">冒号课堂§4.4：情景范式</a> (0)</li><li>2009年09月17日 -- <a href="http://blog.zhenghui.org/2009/09/17/colon-class-4_3/" title="冒号课堂§4.3：汇总范式">冒号课堂§4.3：汇总范式</a> (5)</li><li>2009年09月15日 -- <a href="http://blog.zhenghui.org/2009/09/15/colon-class-4_2/" title="冒号课堂§4.2：逻辑范式">冒号课堂§4.2：逻辑范式</a> (0)</li><li>2009年09月13日 -- <a href="http://blog.zhenghui.org/2009/09/13/colon-class-4_1/" title="冒号课堂§4.1：函数范式">冒号课堂§4.1：函数范式</a> (0)</li><li>2009年09月11日 -- <a href="http://blog.zhenghui.org/2009/09/11/colon-class-3_4/" title="冒号课堂§3.4：事件驱动">冒号课堂§3.4：事件驱动</a> (2)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/06/colon-class-2_3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

