在GNU Smalltalk中使用和不使用“new”创建的实例之间的差异

问题描述 投票:3回答:3

有什么区别

Rectangle origin: 5@5 extent: 40@30

Rectangle new origin: 5@5 extent: 40@30
smalltalk gnu-smalltalk
3个回答
4
投票

Rectangle new origin: 5@5 extent: 40@30创建一个完全初始化的Rectangle实例(准确地说,所有坐标设置为0),然后使用origin:extend:accessor方法设置其坐标和范围。

Rectangle origin: 5@5 extent: 40@30使用Rectangle类构造一个具有给定属性的Rectangle实例,但它认为合适。在GNU Smalltalk的情况下,它使用basicNew消息来分配Rectangle实例而不是新的(see the source of Rectangle)。这放弃了上面变体的“完全初始化的实例”状态:它跳过任何初始化并只分配内存(好吧,GNU Smalltalk文档没有明确说明,但这传统上是basicNew的目的)。然后它使用origin:extend:accessor来初始化新实例的坐标和范围。


3
投票

这是一种风格问题。 Rectangle类提供了用于创建实例的工具方法,以便您可以直接与类通信并编写更少的代码。这也是一个很好的做法,因为你创建矩形对象需要正常工作(这种做法称为RAII,资源获取是初始化)。如果你看一下Rectangle class>>#origin:extent:的来源,你会发现非常类似的东西

origin: aPoint extent: anotherPoint
    ^self new origin: aPoint extent: anotherPoint

所以实际上将消息直接发送到手动创建它的类,然后设置它实际上是相同的


1
投票

我认为重要的是要注意Smalltalk和其他OO语言之间的区别。

在其他OO语言中,您有一个称为构造函数的构造。这使您可以在调用方法new时自动运行某些代码。

例如,你会做红宝石

# Class name   
class ConstructorExample  
    # A constructor  
    def initialize    
        puts "I'm now running constructor"
    end   
end    

# Creating Object 
ConstructorExample.new # upon which calling you will get initialized run automatically.

输出将在您的shell中:

> I'm now running constructor

在Smalltalk你必须区分newbasicNew。 (有时甚至new只是basicNew的别名所以你必须手动运行initialize或创建类方法.basicNew不会自动执行初始化,new通常会(不是所有的方言!)。

上面的例子可以写成:

Object subclass:#ConstructorExample
        instanceVariableNames:''
        classVariableNames:''
        poolDictionaries:''
        category: ''

ConstructorExample>>initialize
    Transcript showCR: 'I'm now running a constructor'


"You would then instantiate"
ConstructorExample new

要么

| example |
example := ConstructorExample basicNew.
example initialize "sending method initialize like any other method"

在这两种情况下,输出都是(在你的成绩单中):

I'm now running a constructor

在我看来,主要原因是,如果你有类方法,你可以在你的一些自定义代码之后运行构造函数

ConstructorExample class >> run
    ^ self basicNew; Transcript showCR: 'Running before constructor'; self initialize; yourself

然后你会做:

ConstructorExample run

输出将是:

Running before constructor
I'm now running a constructor

现在举个例子

作为JayK,melkyades解释了主要的差异,我会给出更多的差异(细节):

第一:

Rectangle new origin: 5@5 extent: 40@30

它实际上是做什么的(没有Transcript showCR:):

| myRactangle |
myRactangle := Ractangle new. "Creates an empty instance with origin: 0 @ 0 corner: 0  @ 0 and would execute initialize if there would be one." 
Transcript showCR: 'Current origin: ', origin asString, 'with corner: ', corner asString. "You should see the zeros"
myRactangle origin: 5@5 extent: 40@30
Transcript showCR: 'Current origin: ', origin asString, 'with corner: ', corner asString. "You should your custom point(s)"

当你做Ractangle new时会发生什么?

Rectangle class >> new [
    "Answer the (0 @ 0 corner: 0 @ 0) rectangle"

     <category: 'instance creation'>
     ^self origin: 0 @ 0 corner: 0 @ 0
]

当你检查源代码时它是sets origin: 0 @ 0 corner: 0 @ 0(注意通过... corner:而不是extent:设置的差异)。

第二:

Rectangle origin: 5@5 extent: 40@30

源代码:

Rectangle class >> origin: originPoint extent: extentPoint
    "Answer a rectangle with the given origin and size"

    <category: 'instance creation'>
    ^self basicNew origin: originPoint corner: originPoint + extentPoint

正如已经指出的那样,有一个qazxsw poi阻止任何qazxsw poi构造函数手动或通过类方法运行,如上所示。

如果你需要,你可以做什么重写它。您将创建自己的矩形类,它将从Rectangle继承它并在那里重写它。

例如:

basicNew

你要定义的地方:

initialize

然后你会打电话给它:

Rectangle subclass:#ApplicationRectangle
        instanceVariableNames:''
        classVariableNames:''
        poolDictionaries:''
        category: ''
© www.soinside.com 2019 - 2024. All rights reserved.