3

和有什么区别

Rectangle origin: 5@5 extent: 40@30

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

3 回答 3

4

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

Rectangle origin: 5@5 extent: 40@30让类 Rectangle 构造一个具有给定属性的 Rectangle 实例,但是它认为合适。对于 GNU Smalltalk,它使用 basicNew 消息来分配 Rectangle 实例而不是 new (参见 Rectangle 的源代码)。这放弃了上述变体的“完全初始化实例”状态:它跳过任何初始化并只分配内存(嗯,GNU Smalltalk 文档没有明确说明,但这通常是 basicNew 的目的)。然后它使用 origin:extend: 访问器来初始化新实例的坐标和范围。

于 2019-03-24T18:07:43.503 回答
3

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

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

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

于 2019-03-24T16:47:52.883 回答
1

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

在其他 OO 语言中,您有一个称为构造函数的构造。这使您能够在调用 method 时自动运行某些代码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.

输出将在您的外壳中:

> 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:和 not设置它的区别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

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

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

例如:

Rectangle subclass:#ApplicationRectangle
        instanceVariableNames:''
        classVariableNames:''
        poolDictionaries:''
        category: ''

您将在其中定义:

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

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

然后你会调用它:

ApplicationRectangle origin: 5@5 extent: 40@30
于 2019-03-26T15:29:42.223 回答