3

我在 Pharo Smalltalk 中编写课程,但我认为这个问题对其他 Smalltalk 实现有效。

我知道一种强制实例具有特定属性的方法是提供一个类方法来创建实例,然后建议使用类创建方法。但是任何用户都知道 new 或 basicNew 可以随时使用。

我曾考虑过使 new 和 basicNew 无效并引发异常,但这似乎过于激进,因为有时我可能需要创建实例以进行调试。

是否有另一个库或机制来强制完成这些特定属性?

4

2 回答 2

8

那没有。这很好。

不过,您可能会遵循以下一些方法:

  1. 通过为它们提供验证来确保您的对象是有效的。这是一个非常广泛的话题,所以我只会说验证框架能够检查您的对象并以某种方式使其明确任何他们未能遵守的规则。

    根据您所做的事情,您可能会在对象生成或修改时将验证限制在 GUI 内。然而,更复杂的方法应该允许任何对象决定它是否有效(在给定的上下文中)。

  2. 从实例端协议中排除单个设置器。仅提供多个关键字设置器,如果缺少某些内容或不合适,这些设置器将失败。这意味着您将提供类似Point >> #x:y:但不提供Poit >> #x:或的方法Point >> #y:

    正如示例所暗示的,您会发现很难充分利用这种做法,因为基本类不遵循这种风格。另请注意,这种做法将需要某种验证,因为仅检查notNil通常过于幼稚。

  3. 放松,什么都不做,直到需要解决这些问题。

    换句话说,将问题推迟到您的软件发展到足以引起您注意其对象的创建和更改方式为止。

我声称事情之所以好的原因是因为 Smalltalk 传统上更倾向于开放而不是安全,它促进甚至鼓励人们进行实验,即使是以“错误”的方式。旨在防止对象被破坏的每个功能,迟早会阻止您修复它们。更重要的是,它们会消耗大量能量,而这些能量原本可以用于更高效的目的。

于 2017-07-25T20:55:27.343 回答
2

我同意莱安德罗的回答。防御性编程很少是 Smalltalk 的做事方式。没有强制执行任何操作的静态类型,也没有私人消息。Smalltalk 是开放的和后期绑定的。但另一方面,错误很少是灾难性的(Smalltalk 通常不会因错误而崩溃)。

这种后期绑定以及优雅的错误恢复使系统的演变成为一个非常轻量级的过程。当您在 Smalltalk 中编程时,如果您想到它,您除了让实时系统发展之外什么都不做。

由于我们唯一要做的就是发送消息,因此我们最终可以使用它来协商合同,或者只是验证一些先决条件。

通过使用 Exception,您建议的策略是可能的。这个想法是,有时最好有一个最接近根本原因的早期异常,而不是一个更难调试和更正的晚期异常。例如查看消息#shouldNotImplement及其发件人:您会看到它有时用于防止使用#new.

另外不要忘记,有一条#initialize消息可以用来给实例变量一个合理的默认值(有点像C++的默认构造函数)。当您想要传递其他信息时,有一些变体:对于通常通过创建的集合,#new:有一条#initialize:消息将大小作为参数。您可以随意改进类似的机制,以便在创建时传递其他信息。

但不要试图阻止使用#basicNew. 你会破坏一些依赖于这个低级特性的服务,比如在你修改你的类布局时改变现有实例,比如复制,比如存储在外部文件中等等,你会给自己带来痛苦……参见#adoptInstance:例子。

相反,您必须学会信任图书馆的用户(包括您自己):basicNew除非用户知道自己在做什么,否则他们不会使用(他们迟早会知道)。正如阿莫斯所说,在课堂或消息评论或单元测试中记录合同和期望,以便人们可以更快地学习,当你想表达一条消息仅供知识使用时,也许可以使用像 basicNew 这样不那么吸引人的名字。

顺便说一句,如果您禁止basicNew,您将根本无法创建实例,因此您必须创建一条新消息来调用创建实例的原语,最后您将获得混淆/复杂的代码什么都没有,因为你只是转移了问题。除非你做非常讨厌的事情,比如:

basicNew
    thisContext sender method selector == #mySepcialCreationMessageWithParameter: ifTrue: [^super basicNew].
    ^self error: 'new instances should be created with mySepcialCreationMessageWithParameter:'

正如我上面所说,你可以玩它,但不要真的去做。

编辑 2另一种观点是编码是一种社交活动,您在 Smalltalk 中编写的代码不仅仅是用于编写自动机。它是为了被人类阅读和重用。在这种情况下,防御性编程有点像通过强制进行管理。与其浪费时间试图进行约束,不如花时间创建易于理解和重用的简单且符合逻辑的抽象,这可能会在您未预见到的其他情况下更有效。

于 2017-07-27T06:55:06.037 回答