目录
- 8.1 示例:编辑器文本类
- 8.2 示例:配置参数
- 8.3 做过了头
- 8.4 结论
本章介绍了另一种思考如何创建更深层次类的方法。假设您正在开发一个新模块,并且发现了一个不可避免的复杂性。哪个会更好呢:应该让模块的用户处理复杂性,还是应该在模块内部处理复杂性? 如果复杂性与模块提供的功能有关,那么第二个答案通常是正确的。大多数模块的用户都比开发人员多,所以开发人员比用户遭罪更好。作为一个模块开发人员,您应该努力使您模块的使用用户生活的尽可能轻松,即使这意味着您需要额外的工作。表达这一思想的另一种方式是, 对于模块来说,拥有一个简单的接口比简单的实现更重要。
作为一名开发人员,很容易采取相反的方式:解决简单的问题,把困难的问题推给其他人。 如果出现不确定如何处理的情况,最简单的方法是抛出异常,让调用者处理它。如果您不确定要实现什么策略,您可以定义一些配置参数来控制策略,并让系统管理员为它们找出最佳值。
这样的方法在短期内会使你的生活更容易,但它们会增加复杂性,因此许多人必须处理一个问题,而不是一个人。例如,如果一个类抛出一个异常,那么该类的每个调用者都必须处理它。如果类导出配置参数,则每个安装中的每个系统管理员都必须学习如何设置它们。
8.1 示例:编辑器文本类
红尘小说网 https://www.zuxs.net/考虑为GUI文本编辑器管理文件文本的类,这在第6章和第7章中讨论过。该类提供了将文件从磁盘读入内存、查询和修改文件在内存中的副本以及将修改后的版本写回磁盘的方法。当学生必须实现这个类时,他们中的许多人选择了一个面向行的接口,该接口具有读取、插入和删除整行文本的方法。这导致了类的简单实现,但也为更高级别的软件带来了复杂性。在用户界面级别,操作很少涉及整行。例如,击键会导致在现有行中插入单个字符;复制或删除选择项可以修改几个不同行的部分。使用面向行的文本界面,为了实现用户界面,高级软件必须分割和连接行。
面向字符的接口(如6.3节中描述的接口)将复杂性拉低。用户界面软件现在可以插入和删除任意范围的文本,而不需要分割和合并行,因此变得更加简单。text类的实现可能会变得更加复杂:如果它在内部将文本表示为行集合,那么它将不得不分割和合并行来实现面向字符的操作。这种方法更好,因为它封装了文本类中分割和合并的复杂性,从而降低了系统的整体复杂性。
8.2 示例:配置参数
配置参数是一个向上而不是向下移动复杂性的例子。类可以导出一些控制其行为的参数,而不是在内部确定特定的行为,例如缓存的大小或放弃之前重试请求的次数。然后该类的用户必须为参数指定适当的值。配置参数在当今的系统中非常流行;有些系统有数百个。
支持者认为配置参数是好的,因为它们允许用户根据自己的特定需求和工作负载调整系统。在某些情况下,底层基础结构代码很难知道应用的最佳策略,而用户对他们的域要熟悉得多。例如,用户可能知道某些请求比其他请求的时间要求更严格,因此用户为这些请求指定更高的优先级是有意义的。在这种情况下,配置参数可以在更广泛的领域内获得更好的性能。
然而,配置参数也为避免处理重要问题并将其传递给其他人提供了一个简单的借口。在许多情况下,用户或管理员很难或不可能确定参数的正确值。在其他情况下,只需在系统实现中做一点额外的工作,就可以自动确定正确的值。考虑一个必须处理丢失的包的网络协议。如果它发送了一个请求,但是在特定的时间段内没有收到响应,它将重新发送请求。确定重试间隔的一种方法是引入配置参数。但是,传输协议可以自己计算一个合理的值,方法是测量成功请求的响应时间,然后对重试间隔使用该时间的倍数。这种方法降低了复杂性,使用户不必确定正确的重试间隔。它还具有动态计算重试间隔的额外优点,因此如果操作条件发生变化,它将自动调整。相反,配置参数很容易过时。
因此,您应该尽可能避免配置参数。在导出配置参数之前,先问问自己:“用户(或更高级别的模块)能够确定比我们在这里确定的更好的值吗?”当你创建配置参数时,看看你是否能自动计算出合理的默认值,这样用户只需要在特殊情况下提供值。理想情况下,每个模块应该完全解决一个问题;配置参数导致解决方案不完整,增加了系统的复杂性。
8.3 做过了头
当把复杂性往下传递时要谨慎,这种想法很容易被夸大。一种极端的方法是将整个应用程序的所有功能都放到一个类中,这显然是没有意义的。如果(a)被降低的复杂性与类的现有功能密切相关,(b)降低复杂性将导致应用程序中其他地方的许多简化,(c)降低复杂性将简化类的接口,那么降低复杂性是最有意义的。请记住,目标是最小化整个系统的复杂性。
第6章描述了一些学生如何在反映用户界面的text类中定义方法,例如实现backspace键功能的方法。这似乎是件好事,因为它将复杂性向下传递。但是,将用户界面的知识添加到text类并不能简化高级代码,而且用户界面知识也与text类的核心功能无关。在这种情况下,降低复杂性只会导致信息泄漏。
8.4 结论
在开发模块时,寻找机会让自己承担一些额外的痛苦,以减少用户的痛苦。