日历

November 2009
M T W T F S S
« Oct   Jan »
 1
2345678
9101112131415
16171819202122
23242526272829
30  

《冒号课堂》意见收集

致读者

《冒号课堂》业已上市,如果您在本书中发现任何谬误或疑问,或对本书有任何意见或建议,敬请回复此帖。小至标点符号,大至思想观点,但凡有疑,尽可畅所欲言,笔者将不胜感谢!

本着对读者负责的精神,若发现书中错误,本博将及时勘正;若发现不够详尽之处,本博将另行补充。

郑晖

2009年11月7日

后记

本帖已成deprecated API,不建议读者继续在此回复。对本书如有疑问或建议,请移步冒号论坛

Be Sociable, Share!

相关文章

分享/保存
 请您评分1星(很差)2星(不行)3星(一般)4星(不错)5星(很棒)

59 comments to 《冒号课堂》意见收集

  • kaven276

    那么对于像 oracle pl/sql 这样的存储过程范式不是也非常重要和使用吗?
    包括 pl/sql server page 这样比 jsp,asp,php 更具优势的架构。

    • 存储过程当然很重要。其重要性不仅仅体现在它能提高运行效率上,还体现在它提供了最贴近数据库的抽象层。事实上,本书在“§5.1:教学计划”中特意提到了存储过程的重要性。当然,这个抽象层的边界界定也是很重要的,如果把所有的业务逻辑都埋在其中,也未必是合适的。
      此外,似乎没有存储过程范式的说法,PL/SQL也是一种过程式编程语言(oracle 8以后还融入了OO的部分特性)。

  • kaven276

    使用 pl/sql server page 做web应用,至少有以下独特的优势:
    1、不用管内存分配、内存释放。
    2、数据直接在表里,不用做 or-mapping
    3、pl/sql 纯程序,无状态,重新修改编译对运行中的系统影响极小
    4、不需要配置如何连数据库,因为本身就在数据库中
    5、支持 table%rowtype,table.column%type 支持 insert into rowtype,update table set row=rowtypevalue,不用再把数据库中的数据结构再到程序中重新定义一遍
    6、主要书写静态sql,没有sql注入风险,在数据库中保持pared version,执行效率更高。
    7、可以连程序到sql一起调试
    8、执行后台任务,dbms_scheduler可以很好配置各种定时策略
    9、可以使用 oracle resource manager 机制,控制那些进程和程序优先占用资源,并在系统不忙时自动进行maintance类的程序。
    10、具有比较强大的正则表达式支持,从oracl10g开始
    11、支持 native compile,对于非sql密集型的程序效率大大提升
    12、存在 pl/sql developer 这样的IDE,响应快占用资源少,但是功能非常强大。充分利用了数据字典。
    13、可以分析出程序在源码的执行路径、可以分析出每部分程序执行消耗的资源,在PSD中非常容易得到
    14、支持 alert/pipe/queue 等异步编程机制
    15、可以通过 dblink/gateway 和其他oracle,其他数据库和其他消息队列进行数据通信;
    16、可以通过 external procedure 和其他基于c和java得程序进行通讯
    17、可以将java程序部署到数据库中在一个进行中同时执行pl/sql和java,可以pl/sql调用java,也可以java调用plsql.
    18、利用 oracle 的内存管理,永远不用担心分配不出内存。因为oracle对程序区、数据缓冲区等都有独立的cache或buffer,且能很据各部分使用情况动态调整。因此当内存需求大的情况,最多响应慢些,但是不会分配不出内存。
    19、如果一个 pl/sql 和 psp 程序编译过了,那么除生成的html页外,后台部分的可靠性就已经非常强了,很少出现运行时出异常的情况。
    20、可以使用 pl/sql oo,直接可以建 object table,object view,支持封装、继承;虽然我认为其实没有必要,但是对于痴迷oo的同志也很不错。
    21、可以通过数字字典进行元编程、反射等模式,可以动态执行 pl/sql 和 sql,虽然应该尽量使用静态调用。
    22、通过数据字典和PSD IDE,可以非常方便的查看被谁引用,而不仅仅是引用谁。
    23、程序包体编译后,只会影响自己,只要包头没变,不会造成级联响应。即使包头改变,也仅影响使用的包体,而不是连带他们的包头从而造成无法控制的级联响应,最终僵死运行中的系统。
    24、不用在设置配置文件和日志文件,全部使用数据库表,同时可以基于表设置相应的配置界面和查询日志界面,而其他非基于数据库的架构就缺少此便利性。
    25、可以查看所有的程序的属性比如创建和最后修改时间等,可以编写system trigger,相当于 AOP机制,自动记录程序变更版本记录,控制并发修改,查询版本差异,回退等。
    26、可以使用 rule manager 进行基于规则的开发
    27、可以使用bulk sql进行批量绑定sql,大大提升效率,并简化编程
    28、支持条件编译,以适应不同的oracle版本和发行环境
    29、版本兼容性好,由于其间接性,10年来在 pl/sql 上没有什么变化,只是增加语言特性和API。
    30、对于动态输出 html,其实已有的几种方式(直接打印字符串到页面、模板页嵌代码、taglib、oracle自己的页面输出API)都有很大局限性,我设计一套页面打印 API,可以用最少最简洁和易懂的代码输出页面,包括输入项options的成组标记、向table-form,table-list的常见模式,包括基于表和视图生成基准代码等,包括局部 css,包括 a/link/img/script 等需要 url 地方的 u:xxx 命名约定。直接支持常见的HTC界面行为组件,包括数、菜单、tabpage、表单录入等等。当然此部分的内容非常多,也不是 oracle 的,而是我给做的扩展 psp.web。只是为了说明输出页面其实有更好的方式,适合于过程式语言输出。
    31、如果一个应用最终就是提供数据管理和界面,那么 psp 其实就是最方便的了。
    32、一个 psp 执行只要从浏览器发送到数据库一个网络请求,然后返回一个页面。如果使用任何中间件,该中间件都要多次访问数据库,增加消耗,包括各种数据类型转换。使用psp,数据类型高度统一。
    33、因为源自数据库,pl/sql,psp从一开始就很好的支持多语言。
    34、真正的跨平台,因为oracle可以在任何主流的os上安装,而对开发人员来说,完全一样。即便是java,也存在各版本各厂商的不兼容性。

    当然,pl/sql,psp,psp.web 虽好,但是 oracle 毕竟很贵,这才是它真正的缺点。

    • 您的总结很全面,非常感谢!
      不过,值得指出的是,这种架构有其可取之处,但也有其不足之处。抛开Oracle昂贵不谈,即使它免费,也不可能完全取代其他数据库。比如,有人更喜欢ODBMS(ODBMS在某些方面可能比RDBMS更优越),有人更喜欢开源的产品,有些应用只需要轻量级的数据库,等等。再说,数据库只是数据持久化技术的一种,也不是在任何时候都是最合适的。更何况,并非所有的应用都是以数据为中心的。此外,如果一个应用的业务逻辑足够复杂,涉及的语言、架构、开发平台等多种多样,此时PL/SQL和PSP即便能胜任,也未必比其他解决方案如JavaEE或.NET更有优势。至于中间件,虽然会增加某些方面的消耗,但在大型分布式应用中,它能有效地提高系统的可伸缩性、安全性、稳定性、可重用性等。
      总而言之,每种架构或技术都有其存在的价值,如何选择和搭配取决于系统需求、软硬件资源、开发人员的技术结构等诸多因素。

  • clevercui

    请问有无逻辑式具体的应用示例啊?例如,一个多段物流系统(即需要分段运输),这个物流系统承担的运输任务的运输路径是预先定义好的,物流系统同时承担多个这样的任务(任务很多,以至运输工具成为瓶颈资源)。若需要根据各任务情况计算最优的传输次序(使所有任务的完成时间最短),能应用逻辑式吗?以前我都是用命令式完成的,中间遇到了很多的困难,内存等各方面的管理,if else语句弄得我头都大了,我非常渴望有一种方式来重新诠释算法,不知道这里逻辑式是否可行?应当如何分析。由于已经习惯了命令式的思维方式,一时难以转化。不知冒号是否能点拨一二?万分感谢

  • Todd

    明显感觉范式部分容易理解,读起来顺畅;而OO部分看过一遍之后还不容易掌握要领。

    • 范式部分是粗讲,且各范式特点鲜明,故相对容易些;OO部分是精讲,涉及到的细节、知识点、设计思想和理念较多,故相对复杂些。
      如果你对某些论述、观点等有疑惑或有不同看法,不妨具体指出。谢谢!

  • Todd

    OO部分篇幅已经不小,但其中很多东西也只能一笔带过,所以希望有机会(或许下一本书,或许博文)就一些专题做更深入地讲解。

    比如,关于单元测试,书中提到过是保证语义正确性的手段,就这点也是我最近才有较深体会的,但可能对于经验较少的程序员来讲需要更多的篇幅来介绍。理解了单元测试意义的程序员,对于动态类型语言会有更深的认识,不会武断地认为其代码质量不如静态类型语言。因为,从某种意义上讲,动态类型语言程序员更习惯于用单元测试保证语义正确性;而静态类型语言程序员容易产生对编译器的依赖性,恰好语义正确性是无法依赖它的。语法可以依赖编译器,语义应更多地依赖单元测试。

    还有其他的地方,以后慢慢列举。

    • 你提到的单元测试虽然重要,但略有些偏离本书的主题,故未详加介绍。类似的还有契约式设计,其重要性可能更高,并且极受忽视,同样由于主题和篇幅的原因而只是蜻蜓点水。看起来,还是找机会另作专题介绍更合适些。
      欢迎继续提出问题!

  • deadbaby

    首先,你的书让我看了很惊讶,我的知识竟然是如此的浅薄。
    其次,书中的建议和最佳实践在我经历的项目中看到的并不多,但项目依然赚钱
    第三,你的知识充实了我的大脑
    第四,问一个书中曾出现的问题:如果你是一个想踏入软件行业的程序员,你该如何选择今天繁杂的语言?我曾经面临JAVA和C#的选择问题,请你给一个你的个人想法,仅仅是如果你要进入软件行业你会选择那门语言?你选择的依据。

    • >>首先,你的书让我看了很惊讶,我的知识竟然是如此的浅薄。

      这正应了本书序言中的一句话:认识到不足何尝不是学习的一种收获呢?

      >>其次,书中的建议和最佳实践在我经历的项目中看到的并不多,但项目依然赚钱

      这个太不奇怪了。项目赚钱与软件质量不能说毫无关系,但关联系数很小。在中国尤其如此。从某种程度上看,正是这样的现实促使许多程序员在变得优秀之前,便“成功”地转型或转行了。

      >>第三,你的知识充实了我的大脑

      谢谢你大脑的接纳。

      >>第四,问一个书中曾出现的问题:如果你是一个想踏入软件行业的程序员,你该如何选择今天繁杂的语言?我曾经面临JAVA和C#的选择问题,请你给一个你的个人想法,仅仅是如果你要进入软件行业你会选择那门语言?你选择的依据。

      语言是程序员永恒的话题。在书中我是不便依据个人喜好来回答这个问题的,即使在这里你可能得不到满意的答案,因为我的答案还是在书中。如果稍微再具体些,再主观些,那么不妨这么说:从事系统编程,选择C、C++(有时甚至需要汇编语言)。从事大型企业级开发,选择Java或C#(从语言特征而言,C#更胜一筹;从开发平台和资源来看,Java更有优势)。选择它们不是因为它们的语言本身有多大的优势,而是现实因素更多些,具体理由就不多说了。如果从事轻量级开发(不限于网络开发),PHP、Ruby、Python等是不错的选择。其他非主流的语言都有其擅长的领域,不过凡是询问哪个编程语言好的人基本上都不太关心它们,所以略去不提了:)最后,我想说的是,初学者应埋头对一种语言(任何语言都行,只要觉得对个人脾胃)进行深入的学习和实践,到了一定阶段后,就应该抬头接纳其他的语言了。

  • 逆铭

    提一个具体的问题。我长期以来把 DI 和 IoC 当做同义词,甚至还曾把 IoC 误记作 Injection of Control,书上关于二者区别的讲解还是觉得有些抽象,看得云里雾里。

    比如,书中提到 DI 是 IoC 的一种实现方式,还以它为例,395页最下面一段提到的“组件”应该是指被注入、被调用的低层类。我有些想象不出作为“组件”的低层类在哪些情景下会控制作为“客户”的上层类。我的观念上一直是怎样避免客户直接依赖一个具体的组件,这里却全反了过来,让人有些不知所措。

    另外,“控制”二字具体是指什么意思呢?完全掌控一个对象的生死?还是只是调用一个对象的方法?“控制”和“依赖”的本质区别又在哪呢?

    关于DI和IoC这块的问题我现在完全晕掉了,上面提的问题可能也很混乱、不得要领,还望见谅。

    • >>书上关于二者区别的讲解还是觉得有些抽象,看得云里雾里。
      不可否认,这的确是书中最费解的部分之一。由于受篇幅和对话体形式所限,文中未能充分展开,你觉得有些迷惑也是很正常的。本博以后会结合实例,对该问题作更细致的阐述。

      >>我有些想象不出作为“组件”的低层类在哪些情景下会控制作为“客户”的上层类。
      作为一个框架(包括某些库),它必须具备通过一些(底层)类来主导系统流程的能力,此时便有了控制作为“客户”的上层类的需要。

      >>我的观念上一直是怎样避免客户直接依赖一个具体的组件,这里却全反了过来,让人有些不知所措。
      二者并不矛盾,书中443页提到:作为服务的享受者,它尽量通过接口而不是实现类向外界请求服务。。。;作为服务的提供者,它尽量以某些接口为超类型,以鼓励它的客户通过这些接口而不是它本身来请求服务。你是从客户(服务的享受者)的角度来考虑问题的,而IoC是从底层库或框架(服务的提供者)的角度来考虑的。

      >>“控制”二字具体是指什么意思呢?完全掌控一个对象的生死?还是只是调用一个对象的方法?
      在OOP中,“控制”一般只是通过抽象接口来(反向)调用一个对象的方法,(在C这样的过程式语言中,通过抽象的函数指针来调用一个具体的函数)不必掌控对象的生命周期。但DI容器着眼于向各个组件注射依赖对象,通常也负责这些对象的生命周期。

      >>“控制”和“依赖”的本质区别又在哪呢?
      “A控制B”强调的是A在运行期间与B协作时具有主动权和控制权,“A依赖B”强调的是A在编译期间依赖B的语法定义。

      最后,需要提醒的是:互相控制、互相依赖的情形也是屡见不鲜的,不必过于执着于这些概念,关键是要遵守一个重要的原则——针对抽象的接口而非具体的实现来设计和编程。

  • Todd

    我尝试回答您的问题,不对之处欢迎指出:

    >>我有些想象不出作为“组件”的低层类在哪些情景下会控制作为“客户”的上层类。
    举个例子:设计一个需要网络通信的组件,我们把它分为Socket层和业务逻辑层,显然Socket层是底层,业务逻辑层是上层。一般来讲应该是上层调用底层,比如业务层有数据需要发,就调用Socket层接口。但由于Socket是事件源(例如,网络断开,收到数据等事件),事件发生的时候Socket是不知道该如何处理的,它必须通知上层来处理。IoC是为了避免上下两层的相互依赖,Socket层只需要定义一个事件回调接口,有事件它就通过这个接口通知处理者。Socket层是针对抽象的事件回调接口编程的,而业务层应该继承这个接口实现相应业务逻辑。而把业务层对象注入给Socket层对象的过程就叫DI。

    >>“控制”二字具体是指什么意思呢?
    可以这样理解:谁定义接口谁就拥有控制权,谁实现接口谁就被控制。上面例子中,Socket层定义事件回调接口,它是控制者;业务层实现回调接口,它是被控制者。

    • 逆铭

      感谢回复,但还是有一些不明白。

      在这个例子里,按照我的观念,业务逻辑层不能依赖socket层,比如需要通过单元测试来测试业务层逻辑,可以mock出socket层的某个类然后注入到业务层中。根据DIP,这时socket层中的那个类应该是实现了业务层中的接口,如”IDataSender”什么的。即socket层依赖了业务层。而上面解释说,业务层也继承了socket层的一个回调接口,这样不还是循环依赖了么?

      • 业务层依赖IDataSender,让Socket实现IDataSender,这是典型的DIP,无疑是正确的。但IDataSender作为一个发送数据的规范,不能算作业务层的,否则作为通用的Socket库便失去了普适的可重用性。

    • Todd的回答基本上是正确的。“谁实现接口谁就被控制”——书中曾说到,实现接口的目的就是为了被重用,这个“被重用”从某种角度看就是”被控制“。
      “谁定义接口谁就拥有控制权”换成“谁调用接口谁就拥有控制权”可能更准确。假如Socket层仅仅定义了事件回调接口,却从来没有在该层调用它(当然通常这种情况不会发生),也谈不上控制权。

  • Todd

    这就是Framework的责任了,IDataSender和IEventHandler这些可以在Framework中定义,业务层,Socket层都依赖Framework。

    • 逆铭

      意思是不是说,两个类相互依赖,于是二者都提取出抽象的interface放在一个framework里,转而让这两个interface相互依赖,而让实体类实现各自的interface。当实体类需要彼此的时候则通过控制注入来满足各自的需求。不知道我理解得对不对?

      但这样的话,按照“谁定义接口谁就拥有控制权,谁实现接口谁就被控制”的说法,就谈不上socket层控制业务层了,也谈不上控制的“反转”了。

      • >>两个类相互依赖,于是二者都提取出抽象的interface放在一个framework里
        未必是一个Framework(事实上一个系统显式地依赖某个Framework不一定是好选择,因为这是一种重量级的依赖),只要这个interface是普遍接受的规范即可(最好是语言自带的核心基础库)。

        >>但这样的话,按照“谁定义接口谁就拥有控制权,谁实现接口谁就被控制”的说法,就谈不上socket层控制业务层了,也谈不上控制的“反转”了。
        1.我在前面的回复中把Todd的“定义接口”改成了“调用接口”。
        2.控制反转依然是存在的:Socket层通过接口反向调用了外界的处理Socket事件的方法,这便是控制反转。至于这个实现来自何处并不重要,虽然最终的确是来自业务层的。

    • >>IDataSender和IEventHandler这些可以在Framework中定义,业务层,Socket层都依赖Framework
      IDataSender通常不会选择在Framework中定义,而是在语言的基本库中定义。否则,一个通用的Socket库依赖某个特殊的Framework是不合情理的。IEventHandler如果特指Socket事件的处理器,则可在Socket层定义。

  • 逆铭

    再多问几句:

    通过DI实现IoC,究竟是invert了谁对谁的control?

    在使用DI容器前,当A需要B来协助完成任务的时候,会自己new一个B出来,再调用它。这时应该是A在control B。现在引入了DI容器,无非是需要B的时候不再自己动手,而是向容器要,然后再和以前一样调用它(不过这时候B应该是个接口了)。但这时候似乎并没有从A control B变成B control A,具体“inversion”体现在哪里呢?

    • >>在使用DI容器前,当A需要B来协助完成任务的时候,会自己new一个B出来,再调用它。
      如果A是低层的B是高层的,要实现控制反转,A不可能自己new一个B来,因为低层不应该依赖高层(事实上也不知道高层,故无法通过new来创建对象),这正是IoC的关键所在。方法之一是依赖注射,另外一个方法是依赖查找(比如通过工厂模式,或通过对所在容器的上下文context的lookup)。这便是书中所说的常用的两种实现IoC的方式。有时也能通过(除constructor和setter之外的)API中的(具有抽象类型的)方法参数来实现。
      清楚了这一点,你的问题似乎迎刃而解了吧?

      • 逆铭

        是不是可以这么理解:A在低层,B在高层,然而A需要B来协助完成任务。但是由于低层类A不应该依赖高层类B,它不能自己创建B。这时可以通过依赖注射、依赖查找或传参的方法帮助低层的A无需自己动手构造B就能获得它。

        还是有几点疑问:
        1. 在这个例子里,是从不该出现的“A手动构造B”变成了“A通过第三方获得B”。但在运行时仍然是由A来调用B,即由A来控制B,并未变成B控制A。反转体现在哪里呢?
        2. 在实际中,DI容器的用途是不是还是“高层的A获得低层的B”这种情况更常见呢?这时反转又如何体现?由于DI框架往往自称“IoC框架”,我总觉得它的使用大部分都是由于IoC的。

        不知道我是不是有些钻牛角尖了,还请不要见怪~

        • >>即由A来控制B,并未变成B控制A。反转体现在哪里呢?
          A是底层,B是高层,底层反调高层即是控制反转。反转体现在:通常是高层应用程序调用低层库或框架,而这里是倒过来的。

          >>在实际中,DI容器的用途是不是还是“高层的A获得低层的B”这种情况更常见呢?这时反转又如何体现?
          DI容器中的控制反转通常指组件把创建并管理所需依赖的控制权交给了容器,但同时也体现在另一方面:组件在服务过程中反向调用来自应用层的(被注入的)依赖。(见《冒号课堂》359页的插语4)
          DI容器的用途是解决系统中组件的依赖获取问题。这样既减轻了组件开发者的负担,又降低了组件之间的耦合度(组件之间不直接依赖,而是通过接口来互相调用。至于具体的对象由DI容器管理,程序员可通过metadata来定制)。如果你使用过类似Spring、Guice的框架,一定会切身体会到这样做的好处。至于是“高层获得低层”(高层不通过IoC也能获得低层,但仍然可以利用DI机制),还是低层获得高层,或者是同层之间的依赖,对于DI容器来说都不是太重要了。

          >>DI框架往往自称“IoC框架”
          不独DI框架,几乎所有框架都有IoC的特征,这也是框架区别于普通(类)库的地方。

          >>不知道我是不是有些钻牛角尖了,还请不要见怪~
          不会的,想成为优秀的程序员就是要有这种钻研精神。

  • 逆铭

    一处小笔误。376页,第三行“不少在”是否应为“在不少”?

  • Todd

    从继承机制那章第一次听说了子类和子类型的区别。以前也看过长方形正方形继承关系问题,但是没有抓住本质,现在从LSP和DbC的观点来看就把握住本质了。另外,后来我在网上一查才发现原来Liskov就是08图灵奖的那位阿姨,据说还是第一位女性图灵奖获得者。

    抽象,封装,继承,多态讲得很深入,把OOP的来龙去脉都理清楚了。

  • Todd

    Liskov那篇论文的题目data abstraction and hierarchy真是太经典了,简单的几个词就把OOP的精髓表达出来了。

  • Todd

    有一个建议,后面OO部分,每节篇幅都比较长,读起来有时候感觉比较吃力。如果分段,每段有一个小标题更有助于理解。

  • Todd

    最近对OOP类型系统的理解开始逐渐深入了,才发现子类型多态、泛型、动态类型、Duck类型,其实都是关于类型间代换关系的。开始有点儿体会到类型系统的数学味道了:)

  • dbhrscom

    挑灯夜读《冒号课堂》数日,最大斩获来自书中关于OOP上升到思想之深,哲学之美,甚幸能结识此书!期待“老冒”更多的精彩。

    按照我的理解,从“编程范式与OOP思想”的命题来看,书中采用生动的对话体,平实的语言丝毫不影响本书的“高级”定位,这或许是最好的表达方式。但书中过大的“程序设计语言”篇幅,私下觉得是一个小小的遗憾,并不是说“程序设计语言”不该谈,只是建立在分类和比较的阐述难免流于论坛式的语言之争,虽费劲口舌,但收效甚微。进而影响到本书在读者心中的定位。

    小小建议:思想是根基,程序设计语言是工具,若能把程序设计语言对编程思想的支持融入到“编程范式和OOP思想”的讲述当中,或是一种更好的策略。

    • >>建立在分类和比较的阐述难免流于论坛式的语言之争,虽费劲口舌,但收效甚微。进而影响到本书在读者心中的定位。
      此言有理。其实书中关于编程语言的部分原本不在计划之列的,只是因为一些网友的强烈建议才临时加入的。该部分确有偏离全书主题之嫌,且评论语言从来是件吃力不讨好的事情。作为佐料,该部分在为某些读者助兴的同时,也败了另外一些读者的兴。

      >>若能把程序设计语言对编程思想的支持融入到“编程范式和OOP思想”的讲述当中,或是一种更好的策略。
      此言甚是!本人确有此意,在书中也局部地采用了这种方式,但限于时间和篇幅,远远未能尽意。或许在以后的博客中会弥补这个缺憾。

      最后,谢谢您的谏言!

  • P11 原文“句号若有所悟:‘所以好的语言就是适合编程者和解决对象的语言’”,感觉上这句有点难理解,我理解了好半天才弄明白作者想说的是“所以好的语言就是适合编程者的语言”,“所以好的语言就是适合解决对象的语言”。
    主要是断句的问题:
    ‘所以好的语言就是适合|编程者|和|解决对象|的语言’,
    ‘所以好的语言就是|适合编程者|和|解决对象|的语言’,
    如果用第二种断句方式,原句可改为‘所以好的语言就是|适合编程者|和|(能)解决问题|的语言’。

    对于标注黑体的要点,要是有理解歧义,挺头大的。

    吹毛求疵了,不过对于这样一本好书,实在是应当出第三版,第四版。
    中文原创书籍不多,精品就更少,郑老师要挺住,将这本书出个十几二十版。

    • 中文分词和断句的确是个头痛的问题,你的最后理解是正确的(采用第一种断句方式)。如果结合上文应该不会产生歧义,但单独看这一句的确有产生误解的可能。你提议的改法并不完全等同原文之意,因为(能)解决(某类)问题的语言很多,但并不是所有的语言都适合。如果原句改为“所以好的语言就是既适合编程者和又适合解决对象的语言”,虽然更清楚了,但又似嫌啰嗦。或许,在“编程者”和“解决对象”下面分别加上下划线更好?

  • Todd

    刚看完间接原则和依赖原则,这部分写得非常流畅。虽然内容基本都是原先了解的,但是读完之后还是有很多收获,主要是通过“规范、抽象、间接、分离、依赖、控制、接口、服务“把各个设计原则都串联起来了。

    另外,有几个具体的问题:
    1.文中提到的多态合成与桥接模式是一回事情吗?
    2.MVC模式我了解不多,也很少使用的,主要是因为Controller比较烦,理不清。我以前做.NET的WinForm GUI程序,感觉很方便,它也是View与Model分离的,但似乎没有Controller的概念。难道这里是.NET WinForm本身的充当了Controller角色吗?

    • >>文中提到的多态合成与桥接模式是一回事情吗?
      桥接模式的确利用了多态合成,但二者不是一回事,事实上不少设计模式都离不开多态合成。前者是属于设计范畴的模式,后者属于实现范畴的机制。

      >>MVC模式我了解不多,也很少使用的,主要是因为Controller比较烦,理不清。我以前做.NET的WinForm GUI程序,感觉很方便,它也是View与Model分离的,但似乎没有Controller的概念。难道这里是.NET WinForm本身的充当了Controller角色吗?

      在GUI中,Controller与View的联系通常很紧密,为了简化设计,不少的GUI Framework都没有把二者分开(但Model是一定要分离出来的)。WinForms是如此,Java中的Swing也是如此(UI Delegate是View与Controller的结合)。

  • Todd

    最近我在项目中有个根据int id,产生string key的需求。由于最初的算法非常简单,是直接key = id.ToString(),在所有地方都是直接这样产生key;后来产生key的算法发生了变化,需要加上日期:key = today.ToString() + id.ToString()。这样一来原先散布在代码中的key=id.ToString()都要全部修改。所以,我就抽象了一个string CreateKey(int id)函数出来出来,都改用CreateKey()。

    这是否属于保变原则呢?发现变化,封装变化。

  • Todd

    这个blog如果有专门的Q&A功能就好了,老在一个主题下面回复太长了。

  • 小夜

    冒号,非常感谢您写的书,不仅仅书的内容是精品,更可贵是传播思想的精神。国内这种质量的书太少了,您的书让我真切的感觉到一个老兵对新兵诚恳的建议和帮助,期待您的更多佳作。

  • Very cool site, but you must improve your header graphics.

  • 发现一个笔误:269 第6行,”但为子类设”,是不是但为子类设计? 是不是每找到1个bug,给1刀,呵呵

    自读此书,每每拍案叫绝(有时是拍大腿),满满的感悟,不过一年工作,鉴于工作经验的欠缺,无法形成语言。

    书还要多读几遍才行。

    以后会多来请教:)

    • hui

      多谢你如此认真地看书。不过此处并非笔误,“为。。。计”是一个语式,意为:“为。。。考虑”。或许有些文言化了,让你产生误解,抱歉。
      希望继续找bug,不过如果1刀/bug ,我怕是要破产了:-(

  • 黄亚平

    对于244页的结论“int是long的子类型”存有疑问。
    您在这前面提出两点判断类型B类型A的子类型的依据:
    1.B的取值范围一定不会超过A;
    2.A所能参与的运算B也能参与;
    代换进去得:类型B=int;类型A=long;
    第1点成立,而第2点不成立。
    所以第1点这个条件是错误的,写反了,应该是:A的取值范围一定不会超过B。
    结合第2点得出结论:类型A=int;类型B=long;
    即:long是int的子类型。

    • hui

      未写反。子类型(subtype)的取值范围不超过超类型(supertype),并能参与后者所能参与的运算。int与long满足此二条件,故int是long的子类型。

  • Hello, always i used to check blog posts here early in the dawn, because i love to find out more
    and more.

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  

  

  

This blog is kept spam free by WP-SpamFree.