Smalltalk 设计原则:Dan Ingalls 谈多态与模块化
来源标题:Design Principles Behind Smalltalk (2001)
Smalltalk 核心设计原则强调多态:程序只应指定对象的行为,而非其表示方式。例如不应声明某对象是 SmallInteger 或 LargeInteger,而只应声明它响应整数协议。这种通用描述对真实世界建模至关重要,例如在交通模拟中新增街道清扫车时无需大量重编译。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
上述原则的这一条款很重要,因为它确保系统会按照设计意图被使用。换句话说,一段旋律可以临时用一组整数来表示音高、时值和其他参数,但如果语言能像处理整数一样轻松地处理音符(Note),用户自然会用音符的集合来描述旋律。在设计每个阶段,只要系统提供了合适的表示方式,人就会自然选择最有效的表示。模块化原则对系统中的过程性组件有一个有趣的推论:
多态:程序只应规定对象的行为,而不应规定其表示。这一原则的常规表述是:程序永远不应声明某个对象是 SmallInteger 还是 LargeInteger,而只应声明它响应整数协议。这种泛化的描述对于现实世界建模至关重要。
设想一个汽车交通仿真。这类系统中的许多过程会引用各种车辆。假设有人想加入一辆街道清扫车。如果代码依赖于它所操作的对象,那么做这个简单扩展就需要大量计算(以重新编译的形式),还可能引入错误。消息接口为这种扩展提供了理想框架。只要街道清扫车支持与其他所有车辆相同的协议,就无需做任何改动即可将其纳入仿真:
因子化:系统中的每个独立组件只应出现在一个地方。这条原则有很多理由。首先,如果对系统的增补只需在一个地方进行,就能节省时间、精力和空间。其次,用户更容易找到满足特定需求的组件。第三,如果缺乏恰当的因子化,在同步变更、确保所有相互依赖的组件保持一致方面就会出现问题。可以看出,因子化失败等同于违反模块化。
Smalltalk 通过继承鼓励良好因子化的设计。每个类都从其超类继承行为。这种继承沿着越来越通用的类向上延伸,最终止于类 Object,它描述了系统中所有对象的默认行为。在上面的交通仿真中,StreetSweeper(以及所有其他车辆类)会被描述为通用类 Vehicle 的子类,从而继承合适的默认行为,并避免在许多不同地方重复相同的概念。继承还说明了因子化的另一个实际好处:
杠杆效应:当系统良好因子化时,用户和实现者都能获得巨大的杠杆效应。以对有序对象集合排序为例。在 Smalltalk 中,用户会在类 OrderedCollection 中定义一个名为 sort 的消息。完成之后,系统中所有形式的有序集合都会通过继承立刻获得这项新能力。顺带一提,同一个方法既能给文本按字母排序,也能对数字排序,因为支持文本和数字的类都识别比较协议。
结构化对实现者的好处是显而易见的。首先,需要实现的原语会更少。例如,Smalltalk 中的所有图形都通过单一原语操作完成。只有一项任务要做,实现者就能对每条指令倾注精心关注,因为他知道效率上的每一点小改进都会在整个系统中被放大。人们自然会问:什么样的原语操作集合足以支撑整个计算系统?这个问题的答案被称为虚拟机规范:
虚拟机:虚拟机规范为技术的应用建立框架。Smalltalk 虚拟机建立了面向对象的存储模型、面向消息的处理模型,以及用于信息可视显示的位图模型。通过使用微码乃至最终使用硬件,系统性能可以大幅提升,而不会损害系统的其他优点。
用户界面
用户界面就是一种语言,其中大部分交流是视觉性的。由于视觉呈现与既有人类文化大量重叠,美学在这一领域起着非常重要的作用。由于计算机系统的所有能力最终都通过用户界面交付,灵活性在这里也至关重要。用户界面具备足够灵活性的一个使能条件,可以表述为一条面向对象原则:
反应原则:用户可访问的每个组件都应能以有意义的方式呈现自身,以供观察和操作。这一标准得到了通信对象模型的良好支持。按照定义,每个对象都提供用于交互的适当消息协议。这个协议本质上是一种仅适用于该类对象的微语言。在用户界面层面,屏幕上每个对象的适当语言以视觉方式呈现(文本、菜单、图片),并通过键盘操作和指点设备的使用来感知。
应当注意,操作系统似乎违反了这一原则。在这里,程序员不得不偏离原本一致的描述框架,离开已经建立起来的任何上下文,去处理一个完全不同且通常非常原始的环境。这未必非得如此:
操作系统:操作系统是一堆无法纳入语言的东西的集合。本不该有操作系统。下面是一些传统操作系统组件被自然纳入 Smalltalk 语言的例子:
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。