Разница между экземплярами, созданными с и без `new` в GNU Smalltalk - PullRequest
3 голосов
/ 24 марта 2019

В чем разница между

Rectangle origin: 5@5 extent: 40@30

и

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

Ответы [ 3 ]

4 голосов
/ 24 марта 2019

Rectangle new origin: 5@5 extent: 40@30 создает полностью инициализированный экземпляр Rectangle (чтобы быть точным со всеми координатами, установленными в 0), а затем устанавливает его координаты и экстент с началом координат: extend: метод доступа.

Rectangle origin: 5@5 extent: 40@30 имеет класс Rectangle, создающий экземпляр Rectangle с заданными атрибутами, однако он считает нужным. В случае GNU Smalltalk, он использует сообщение basicNew для выделения экземпляра Rectangle вместо нового (см. Источник Rectangle) . Это исключает состояние «полностью инициализированного экземпляра» в приведенном выше варианте: оно пропускает любую инициализацию и просто выделяет память (ну, документы GNU Smalltalk не говорят об этом явно, но это традиционно цель basicNew). Затем он использует метод origin: extended: для инициализации координат и экстента нового экземпляра.

3 голосов
/ 24 марта 2019

Это вопрос стиля.Класс Rectangle предоставляет метод для создания экземпляра, так что вы можете напрямую общаться с классом и писать меньше кода.Это также хорошая практика, поскольку вы создаете прямоугольный объект со всем, что ему нужно для правильной работы (эта практика называется RAII, получение ресурсов - это инициализация).Если вы посмотрите на источник Rectangle class>>#origin:extent:, то обнаружите что-то очень похожее на

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

Так что на самом деле отправка сообщения непосредственно классу, создание его вручную и установка его на практикеже

1 голос
/ 26 марта 2019

Я думаю, что важно отметить разницу между Smalltalk и другими языками OO.

В других языках OO у вас есть конструкция, называемая конструктором.Это позволяет вам автоматически запускать определенный код при вызове метода new.

Например, в ruby ​​ вы должны сделать

# 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 вы должны различать new и basicNew.(Иногда даже 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

Теперь к вашему примеру

As 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 (обратите внимание нанастройка ifference с помощью ... 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

Как указаноуже существует 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
...