2017-07-25 75 views
3

我正在Pharo Smalltalk中编写类,但我认为该问题对其他Smalltalk实现有效。Smalltalk中的必需属性

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

我想过无效new和basicNew引发异常,但这似乎是太过于激烈的措施,有时我可能需要创建实例来调试例如。

是否有另一个库或机制来执行那些特定的属性来完成?

回答

8

没有。这很好。

以下是你可能会虽然遵循一些途径:

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

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

  2. 从实例端协议中排除单个设置者。只提供多个关键字设置程序,如果某些内容丢失或不合适,将会失败。这意味着您将提供像Point >> #x:y:但不是Poit >> #x:Point >> #y:的方法。

    正如例子所示,你会发现很难完全采取这种做法,因为基础班不遵循这种风格。还要注意,这种做法将需要某种验证,因为只检查notNil通常太过天真。

  3. 放松和不采取任何行动,直到需要解决这些类型的问题。

    换句话说,直到你的软件发展到足以让你注意到它的对象被创建和改变的方式之前,这个问题一直存在。

之所以我要求的东西都是好的,他们现在的样子是因为Smalltalk中,有过安检传统青睐的开放性,方便,甚至鼓励人们去尝试,即使是在“错误”的方式。旨在防止物体被破坏的每个功能迟早会阻止您修复它们。更重要的是,他们会消耗大量的能量,否则这些能量可能会被用于更高效的目的。

+2

我建议选项#3。作为一个对象的作者,你可以(事实上应该)做的一件事就是将你的假设添加到类的评论中。如果你按照“我希望用#newWith实例化”的方式添加一些内容: - 如果你使用#new或#basicNew创建了一个实例,那么可能会发生奇怪的事情“,那么你已经完成了自己的任务并发生了任何问题来自不恰当/意外的实例化是使用你的对象的人的责任。试图预见一切可能的方式,有人可能会做一些奇怪的事情意味着开始一场你很可能失败的战斗。 ;-) –

+0

isValidInContext:anApplicationContext在应用程序级别确实非常有用。 –

2

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

这种延迟绑定以及优雅的错误恢复是使系统演化成为一个非常轻量级的过程的原因。在使用Smalltalk进行编程时,如果您想到这一点,您只会让现场系统发展。

由于我们唯一的事情就是发送消息,我们最终可以用它来谈判合同,或者只是验证一些先决条件。

虽然通过使用Exception,但您建议的策略是可能的。这个想法是,有时候最好有一个尽可能靠近根本原因的早期异常,而后期异常更难以调试和纠正。例如,请参阅消息#shouldNotImplement及其发件人:您将看到它有时用于防止使用#new

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

但是不要试图阻止使用#basicNew。通过打破依赖此低级别功能的一些服务,例如在修改类布局时突变现有实例(如复制,如存储在外部文件等中),您会对自己造成痛苦,例如,请参阅#adoptInstance:。但是,你必须学会​​信任你的图书馆用户(包括你自己):除非他们知道他们在做什么(他们迟早会知道),否则用户不会使用basicNew。正如Amos所说,在课堂或消息评论或单元测试中记录合同和期望,以便人们可以更快地学习,并且可能不会使用像basicNew这样诱人的名字,当你想表达一条消息仅用于知识性使用时。顺便说一下,如果你禁止使用basicNew,你将不能创建实例,所以你将不得不创建一个新的消息来调用创建实例的原语,最后你将会只是混淆/复杂的代码,因为你刚刚取代了这个问题。除非你非常讨厌的东西,如:

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

正如我前面所说,你可以用它玩,但没有真正做到这一点。

编辑2另一个观点是编码是一种社交活动,您在Smalltalk中编写的代码不仅仅用于编写自动机器。它被人类阅读和重复使用。在这种情况下,防御性编程有点像通过强制进行管理。不要浪费时间来限制,而是花时间创建简单和合理的抽象,这些抽象可以很容易地理解和重用,也许在其他情况下,您可能还没有预见到。