Monthly Archives: 九月 2005

SmaCC 指南

翻译:ShiningRay @ Nirvana Studio 原文地址: http://www.refactory.com/Software/SmaCC/Tutorial.htm 这是一个用于演示一些SmaCC(Smalltalk编译器的编译器)的简要指南。在这个例子中,我们会逐步开发一个简易的计算器。 如果你已经做过这种东西,你可以先 载入代码 。你载入了代码之后,你需要打开SmaCC解释器生成器。在VisualWorks 和 VisualAge中,它在Tools菜单下。Dolphin的在一个额外的工具目录中。它会打开一个类似下面的窗口: 我们第一个计算器相对比较简单。它只要能读取两个数字并把它们相加。开始之前,我们首先要告诉扫描程序如何辨认一个数字。数字由一个或多个数字打头,后面可能还有一个小数点加上0或者更多的数字。扫描程序对这个标记的定义是: <number> : [0-9]+ (\. [0-9]*) ? ; 把这行代码输入界面上的scanner标签页中。让我们逐个看每一个部分: <number> 指出记号的名字。在<>中的名称必须是合法的Smalltalk变量名。 : 分隔记号名称和记号定义。 [0-9] 匹配任何一个在’0′到’9′(一个数字)范围中的字符。 + 匹配前面的表达式一次或多次。在这种情况下,我们要匹配一个或多个数字。 ( … ) 标示子表达式组。 \. 匹配 ‘.’ 字符(. 在正则表达式中有特殊的含义,使用 \ 来转义)。 * 匹配前一个表达式零次或多次。 ? 匹配前面的表达式零次或一次。(也就是,前面表达式是可选的)。 ; 终止一个记号说明。 我们不想去关心我们语言中的空白符,所以我们需要定义什么是空白符并且忽略它,输入下面的记号说明: <whitespace> : \s+; \s 会匹配任何空白字符(空格、制表符、换行、回车等等)。然后我们怎么告诉扫描程序去忽略它呢? 如果你看一下SmaCCScanner类,你会发现一个叫做’whitespace’的方法。如果一个扫描程序有一个方法的名称和某个标记一样,那么一旦扫描程序匹配了这类标记就会调用这个方法。正如你所见,whitespace方法会吃掉空白符。同样还有一个’comment’方法会作类似的处理。 说到我们的语法,现在让我们来定义它吧。在Parser表格中输入以下语法说明: Expression [...]

为什么继承是有害的?

通过把具体的基类转变成接口来改进你的代码 作者:Allen Holub  翻译:ShiningRay @ Nirvana Studio 摘要 大多数优秀的设计师避免出现继承(extends描述的关系),就像躲避瘟疫似的。你的代码80%应该完全以接口的方式来书写,而不是继承具体的基类。其实,Gang of Four 这本关于设计模式的书(以下简称GoF)很大程度上关于如何把类继承转变成接口实现。本文将叙述为什么设计师们会有这种古怪的信条。(2,300 words;2003 年 8月 1日) 译注:本文其实已经有人翻译,当时没有具体了解就开始翻译了,如果另一位译者看到这篇文章,希望不要理解为我抄袭的。 extends关键字是很有害的;也许不仅仅是在Charles Mason的级别上,还坏到了只要可能都应该避免的程度。GoF中详细讨论了把类继承(extends)如何转变成接口实现(implements)。 优秀的设计师的大部分代码都是根据接口写的,而不是根据具体的基类。本文将会讲述为什么设计师们会有这种古怪的癖好,同时也将介绍一些基于接口的编程基础。 接口 VS 类 我曾经参加了一个Java用户小组会议,那次刚好是James Gosling(Java的发明者)作特邀演讲人。在那次难忘的Q&A对话(提问)上,一个人问他:“如果你可以重新将Java搞一遍,你会做哪些修改?”“我会去掉类,”他回答道。在笑声渐渐消失之后,他解释了真正的问题不是类的本质,而是类继承(extends关系)。接口实现(implements关系)却是完美的。只要有可能,你们就应该避免类继承。 弹性的丧失 为什么你应该避免类继承?第一个问题是明确的使用具体类的名称会把你框在特定的实现中,让以后的更改会十分困难。 当代,敏捷开发方法学的核心是设计和开发同步。你在完全详细描述程序之前,就开始编写代码了。这种技术完全违背了传统的理念——设计应该在编程之前完成——但是很多成功的项目已经证实了,用这个方法,你可以比传统流水线作业更快速地开发高质量的代码(同时付出很有效)。然而,在并行开发的核心是,弹性的概念。你必须以这种方式来写你的代码,以便你可以尽可能以无痛的方式加入新发现的需求到现有的代码中。 你只要实现确实需要的特性,而不是实现那些可能需要的特性,但要用一种可以适应变化的方法。如果你没有这种弹性,并行开发明显是不行的。 接口编程正是这个弹性接口的核心。要了解为什么,先让我们看看如果你不使用接口会发生什么。考虑以下代码: f() { LinkedList list = new LinkedList(); //… g( list ); } g( LinkedList list ) { list.add( … ); g2( list ) } 现在假设一个紧急的新需求,需要进行更快速的查找,已经暴露出来了,这样LinkedList就达不到要求了,你就要把它换成HashSet。在现有的代码中,因为你必须同时修改f()还有g()(它用一个LinkedList作为参数),因此更改不是局限在一处的,还有一切传列表给g()的地方。 [...]