Абстрактный класс в Smalltalk-Squeak. Что это?

Если я правильно понял, то абстрактный класс — это тот, у которого есть хотя бы один абстрактный метод?

Теперь, если он абстрактный, поэтому я должен быть не в состоянии создавать экземпляры этого класса?

Например, указанный Abst является именем абстрактного класса (поскольку он содержит абстрактный метод), поэтому:

a := Abst new.

является незаконным и должно выдавать ошибку/исключение? или проблема должна возникнуть здесь:

a := Abst class new.

?

ОБНОВЛЕНИЕ: как и было предложено, я сделал следующий метод, который не позволит пользователю создавать экземпляры класса, но он не работает:

makeAbstract: aClass    
    aClass compile: 'new
                ^ self subclassResponsibility'.

person user550413    schedule 02.05.2011    source источник


Ответы (5)


Добро пожаловать в SmallTalk! Одна из замечательных особенностей Smalltalk заключается в том, что он доверяет разработчикам, которые извлекают выгоду из той силы, которая приходит с этим доверием. Поэтому такие слова, как «невозможно» и «незаконно», применяются редко.

Как и большинство других вещей, абстрактные классы в Smalltalk больше похожи на предложение/указатель, чем на жесткий закон. Две подсказки, которые вы ищете, это #subclassResponsibility и #shouldNotImplement. Эти два метода являются подсказками для подклассов, следует ли включать конкретный метод. Проверьте отправителей на наличие примеров на изображении (всегда отличная отправная точка для вопросов).

Поскольку «абстрактный», как описано выше, действительно относится к каждому методу, ваши примеры не будут генерировать ошибку (если только #subclassResponsibility или #shouldNotImplement не вызываются из initialize.

Две маленькие вещи:

  • Имена классов в Smalltalk пишутся с заглавной буквы, поэтому воздерживаться, а не воздерживаться.
  • Поиск в Google проходит долгий путь. Все, что вам нужно, это три из четырех верхних ссылок на "абстрактный класс smalltalk" (эта особенно смотрел прямо на).

ОБНОВЛЕНИЕ: если вы хотите сообщить пользователям вашего класса, что они не должны создавать экземпляры (как в вашем комментарии ниже), вы можете написать:

Abstract>>new
    ^ self subclassResponsibility.

Затем «Абстрактный новый» -> ошибка, но «Абстрактный подкласс новый» в порядке.

Хотя по-прежнему нет гарантии, что AbstractSubclass переопределил абстрактный метод (не #new, а тот, из-за которого вы в первую очередь хотели предотвратить создание экземпляров), на практике это не будет проблемой. Если вы действительно хотите, вы можете установить проверку, возможно, в #initialize, которая гарантирует, что ни один из методов экземпляра не вызовет #subclassResponsibility, но не беспокойтесь, если у вас нет веской причины.

ОБНОВЛЕНИЕ 2: Ваш служебный метод для создания абстрактного класса:

Class>>makeAbstract

    self class compile: 'new
                ^ self subclassResponsibility'.
person Sean DeNigris    schedule 02.05.2011
comment
Спасибо, так что, если нет такой вещи, как незаконная или неспособная, какая на самом деле связь между абстрактным классом и не созданием экземпляров такого класса? Если, например, у меня есть класс, и я добавляю абстрактный метод во время выполнения, а затем (все еще во время выполнения), когда я попытаюсь создать экземпляр этого класса, я хочу, чтобы он сгенерировал ошибку, поэтому он не позволит мне сделать тот экземпляр. Где это должно быть обработано? - person user550413; 02.05.2011
comment
@Sean DeNigris, я пытался это сделать, но при вызове new у меня не было ошибок. См. обновление выше. - person user550413; 02.05.2011
comment
Вы были очень близки. См. мое редактирование тела метода выше (добавлен класс). Ваш код помещает #new на стороне экземпляра. Кроме того, если вы поместите его в класс, вам не нужно передавать имя класса. - person Sean DeNigris; 02.05.2011
comment
@Sean DeNigris, спасибо, теперь все работает. Итак, что я сделал, так это добавил экземпляр? Когда я только что скомпилировал aClass: 'somecode' для других методов, я мог видеть в браузере, что метод был добавлен, поэтому он добавил методы без класса addind, как вы написали. Какая разница? И да, я знаю, что имя класса не нужно, но makeAbstract — это метод, который я добавил в свой собственный класс, а не в сам класс. - person user550413; 02.05.2011
comment
@Sean DeNigris, это как-то связано с метаклассом? - person user550413; 02.05.2011
comment
Метод, который вы написали, добавил метод, но на стороне экземпляра. Когда вы добавляете класс, он добавляет его на стороне класса. Детали — это совсем другой вопрос, и лучше всего их можно понять, прочитав хороший справочник по Smalltalk. Наконец, было предложено поместить метод в класс, а не в ваш класс. Таким образом, вы можете написать Abstract makeAbstract. Другой абстрактный класс makeAbstract. и т.д... - person Sean DeNigris; 03.05.2011
comment
@user550413 user550413 вы можете отправить сообщение isAbstractClass классу, чтобы узнать, является ли он абстрактным, а затем выполнить любое действие, которое вы хотите. isAbstractClass возвращает значение true, если какие-либо методы возвращают значение subclassResponsibility. - person Sean T Allen; 03.05.2011

В Smalltalk вы можете просто создавать экземпляры абстрактных классов. Пока вы не вызываете абстрактные методы, они просто работают. Возможно, вы захотите реализовать отсутствующие методы во время выполнения.

person Stephan Eggermont    schedule 02.05.2011

Да, абстрактный класс должен иметь хотя бы один абстрактный метод, но нет, вы все равно можете создавать экземпляры этого класса.

Что вам нужно сделать, так это создать конкретные классы, которые наследуются от абстрактного класса, для которого вы можете создавать экземпляры и вызывать методы.

Абстрактные методы в Smalltalk имеют особую реализацию, которая делает их и класс абстрактными:

method
    self subclassResponsibility

Это также означает, что подклассы должны переопределять этот метод и предоставлять конкретную реализацию.

Если вы видите ошибку, связанную с subclassResponsibility, ваш код либо вызвал метод абстрактного класса, либо ваш подкласс не предоставил реализацию для этого метода.

person quamrana    schedule 02.05.2011
comment
Я добавил метод, который переопределяет new некоторого класса с помощью ^ self subclassResponsibility, но при попытке создать экземпляр этого класса я не получил ошибок (см. Код в ОБНОВЛЕНИИ выше). - person user550413; 02.05.2011

Я рекомендую вам прочитать книгу «Фаро на примере». Вы можете найти его здесь: http://pharobyexample.org/, и вы найдете много интересного. Это открытая книга, бесплатная, и вы можете скачать ее в формате pdf. На самом деле то, о чем вы спрашиваете, объясняется в главе 5 на странице 88.

person Mariano Martinez Peck    schedule 02.05.2011

(Фиксированный) «новый блокировщик» создает небольшое неудобство для его конкретных подклассов: им придется переопределить new и они не смогут использовать новые функциональные возможности каких-либо унаследованных суперклассов. . Вы можете обойти это с помощью небольшой защиты, которая проверяет, действительно ли это абстрактный класс, который пытается быть создан:

AbstractClass class >> new
    self == AbstractClass ifTrue:[
        ^ self abstractClassInstantiationError
    ].
    ^ super new

(обратите внимание на сравнение идентичности здесь, которое работает, даже если вы разместили несколько абстрактных классов друг над другом)

person blabla999    schedule 29.11.2012
comment
Вы можете увидеть аналогичную проблему (и решение) с абстрактными TestCase в SUnit: ищите разработчиков #isAbstract. - person Frank Shearar; 29.11.2012