Smalltalk в примерах/Создание экземпляра: различия между версиями

Содержимое удалено Содержимое добавлено
Новая: Сейчас мы рассмотрим более подробно как создавать экзэмпляры класса. Основное сообщение для создани...
(нет различий)

Версия от 08:47, 5 апреля 2007

Сейчас мы рассмотрим более подробно как создавать экзэмпляры класса. Основное сообщение для создания экзэмпляра это \emph{новый}, которое возвращает новый экзэмпляр класса. Например,


служащий := Служащий новый.
совокупность := УпорядоченнаяСовокупность новый.

Если ты пошлёш классу совокупность сообщение \emph{новый}, оно вернёт новую совокупность\footnote{Sending new: to a class that is not variable sized will generate an exception}. Размер всегда должен быть нулевым пока совокупность пустая, но вместимость будет равна вместимости по умолчанию для данного класса. Вместимость это количество элементов которые ты можэш поместить в совокупность до того как он начнёт увеличиваться. Например, выполнение следующих выражений даёт вместимость показаную справа.


\begin{verbatim} --- \end{verbatim}

Увеличение вместимости совокупности довольно дорого потому что увеличивающий код создаёт новую совокупность с большэй вместимостью, копирует все элементы текущей совокупности, затем большая совокупность становится новой. Если ты знаеш насколько большой должна быть совокупность, или представляеш начальную вместимость, более эффективно создать совокупность при помощи сообщения \verb|new:| где параметр это начальная вместимость. Некоторые совокупности, такие как Массив, не увеличиваются автоматически, поэтому важно определять их вместимость (для совокупностей которые на увеличиваются автоматически, размер и вместимость это одно и то жэ). Например,


массив := Массив новый: 10.
совокупность := УпорядоченнаяСовокупность новый: 20.
поток := (Поток новый: 100) writeStream.

Методы \verb|новый| и \verb|новый:| реализованы в \verb|Behavior|, однако они переопределены во многих классах. Из за того что твой класс наследует \verb|новый| и \verb|новый:|, ты не должен переопределять их пока твой класс ---. Есть два типа присвоения которые могут быть сделаны: присваивание переменной начального значения по умолчанию, и присваивание переменной значения спецыфичного для экэмпляра. Давай рассмотрим каждый вариант.


Присваивание значений по умолчанию

Допустим у нас есть объект \emph{Сотрудник} который следит за дозволенным и реальным количеством часов простоя и времени болезни. Когда экзэмпляр \verb|Сотрудника| создаётся, мы хотим иницыализировать его переменные экзэмпляра подходящими значениями, не обращая внимания на имя или жалование сотрудника. Есть два способа сделать это. Ты можэш использовать lazy иницыализацыю как мы делали в Главе 4, Переменные. Например,


Сотрудник>>sickHoursUsed
   ^sickHoursUsed неОпределено?
      истина: [sickHoursUsed := 0] 
      лож:    [sickHoursUsed]

В качестве альтернативы, ты можеш иницыализировать все данные в одном методи \verb|иницыализацыя|. Lazy иницыализацыя полезна ести твой объект никогда не использует данные которые сложны для иницыализацыи, но на доступ к данным тратится дополнительное сообщение при каждом обращении. Если ты хочеш ---. Например, для объекта \verb|Сотрудник| мы можэт быть следующий метод иницыализацыи.


Сотрудник>>иницыализацыя
   сам времяБолезни: 0.
   сам время---: 0.
   сам допустимоеВремяБолезни: 80.
   сам допустимоеВремя---: 80.

Для вызова метода \verb|иницыализацыя| ты должэн переопределить метод \verb|новый| т.к. наследуемый \verb|новый| не вызывает \verb|иницыализацыю| (\potom). Обычный способ переопределения \verb|новова| показан в следующем примере (\potom).


класс Сотрудник>>новый
  ^супер новый иницыализацыя

До того как ты переопределиш \verb|новый| как показано здесь, ты должэн знать что \verb|супер новый| существует. Если метод \verb|новый| в суперкласс посылает сообщение \verb|иницыализацыя|, твой метод \verb|иницыализацыя| будет вызван дважды, один раз при вызове метода \verb|новый|, затем второй раз при вызове метода \verb|новый| \emph{Сотрудника}. В этой ситуацыи ты не должэн переопределять \verb|новый| пока ты можэш наследовать его из суперкласса. Т.к. в суперклассе есть метод \verb|иницыализацыя| предположытельно иницыализирует данные суперкласса, твой метод \verb|иницыализацыя| должэн начинаться со строки \verb|супер иницыализацыя|. Например, допустим что есть класс \emph{Сотрудник}, с подклассами \emph{ВременныйСотрудник} и \emph{ШтатныйСотрудник}. Давай примем что временный сотрудник работает две недели а штатный сотрудник работает три недели. Мы можэм получить следующее:


класс Сотрудник>>новый
  ^супер новый иницыализацыя
Сотрудник>>иницыализацыя
  сам продолжытельностьБолезни: 0.
  сам продолжытельностьРаботы: 0.
ВременныйСотрудник>>иницыализацыя
  супер иницыализацыя
  сам допустимоеВремяБолезни: 80.
  сам допустимоеВремяРаботы: 80.
ШтатныйСотрудник>>иницыализацыя
  супер иницыализацыя
  сам допустимоеВремяБолезни: 120.
  сам допустимоеВремяРаботы: 120.

Обычный способ сделать переопределения метода \verb|новый| --- \verb|^супер| \verb|новый| \verb|иницыализацыя|, некоторые люди предпочитают сообщение \verb|простойНовый|.


класс МойКласс>>новый
  ^сам простойНовый иницыализацыя

Методы которые начинаются с \verb|простой|, таких как \verb|проснойНовый| и \verb|простойОт:|, не могут быт переопределены. Их предназначение предоставлять основную функцыональность, и программисты дожны быть способны полагаться на это. Если ты хочеш переопределить функцыональность, переопредели \verb|новый| и \verb|от:|. При использовании \verb|простойНовый|, ты не должэн беспокоиться о том что любой суперкласс пошлёт сообщение \verb|иницыализацыя| и из за этого твой метод \verb|иницыализацыя| выполнится более чем один раз. Однако, ты по прежнему определяеш когда ты должэн посылать сообщение \verb|супер иницыализацыя| в своём методе \verb|иницыализацыя|.


Переопределение метода новый

\potom. Одно из решэний --- наследовать все классы твоей программы от \verb|МояПрограммаОбъект|, который заменяет \verb|Объект|. В объекте МояПрограммаОбъект, ты переопределяеш метод \verb|новый| на стороне класса, и пишыш метод \verb|иницыализацыя| на стороне экзэмпляра. Сейчас ты можэш переопределить \verb|иницыализацыю| в твоём классе без переопределения метода \verb|новый|.


класс МояПрограммаОбъект>>новый
  ^супер просойНовый иницыализацыя
МояПрограммаОбъект>>иницыализацыя
"ничего не делать"

Присвоение экзэмплярам особых значений

Часто когда ты создаёш новый экзэмпляр ты нужнаешся в присвоении ему некоторой информацыи. В нашэм примере сотрудника, мы нуждаемся менее всего в имени. Мы такжэ возможно нуждаемся в задании номера соцыальной страховки, зарплаты и информацыи о поле, материальном положэнии и количестве ---. Есть два пути: создать экзэмпляр а затем присвоить значения переменым, или задать переменные во время создания экзэмпляра. For the sake of example, давай примем что когда создаётся объект сотрудник, две части информацыи абсолютно необходимы: имя и номер соцыального страхования. Если мы создадим экзэмпляр затем присвоим переменные, мы возможно поступим как-нибудь так:


сотрудник := Сотрудник новый.
сотрудник := имя: аИмя.
сотрудник номерСоцыальногоСтрахования: аНомер.

Проблема этого подхода в том что ты полагаешся на то что все программисты не будут забывать присвоить требуемые переменные посел создания экзэмпляра. Это нормально если переменные необязательная, но опасно если она обязательная. Если ты хочеш гарантировать что данные присвоены, лучшэ (better off) написать метод создания экзэмпляра который заставляет программиста предоставить нужную информацыю. Например, если мы напишым наш собственный метод создания, мы можэм создать сотрудникак как здесь:


сотрудник := Сотрудник имя: аИмя номерСоцыальнойСтраховки: аНомер

Как должэн выглядеть метод \verb|имя:номерСоцыальноСтраховки:|? Один из вариантов просто передть методу иницыализацыи информацыю которую нужно присвоить.


класс Сотрудник>>имя: аИмя номерСоцыальнойСтраховки: аНомер
  ^супер новый иницыализироватьИмя: аИмя 
               номерСоцыальноСтраховки: аНомер

Это разумный подход если тебе нужэн метод иницыализацыи для других данных, таких как переменна vocationHoursUsed показаная вышэ. Однако, если метод иницыализацыи не делает ничего кроме присвоения переменным подходящих значений, ты можэш присвоить данные непосредственно. Например, ты можэш использовать одну из следующих техник; ---.


класс Сотрудник>>имя: аИмя номерСоцыальногоСтрахования: аНомер
  | экзэмпляр |
  экзэмпляр := супер новый.
  экзэмпляр имя: аИмя.
  экзэмпляр номерСоцыальногоСтрахования: аНомер.
  ^экзэмпляр
класс Сотрудник>>имя: аИмя номерСоцыальногоСтрахования: аНомер
  ^супер новый
      имя: аИмя;
      номерСоцыальногоСтрахования: аНомер;
      тысам

Переопределение метода новый для предотвращения его использования

Если ты требуеш от программистов использовать \verb|имя:номерСоцыальногоСтрахования:| для создания экзэмпляра \emph{Сотрудник}, ты можэш переопределить \verb|новый| так чтобы он вызывал исключение. Этот способ не очень общий, но он позволяет программисту легко определить что он неправильно создаёт экзэмпляр объекта сотрудник.


класс Сотрудник>>новый
  сам ошыбка:'Пожалуйста используй 
              имя:номерСоцыальногоСтрахования:
              для создания экзэмпляров Сотрудник'

Опасайтесь использовать метод новый:

Если только нужно имя сотрудника, ты можэш временно использовать \verb|новый: аИмя|. Воздержывайтесь от временных решэний. Метод создания экзэмпляра \verb|новый:| используется для задания размера совокупности, и программисты читающие код должны able to assume что создаётся совокупность когда они видят \verb|новый:|. Вместо этого используй \verb|имя:| или \verb|новыйИменуемый:| или \verb|новыйСИменем:|. Я склоняюсь использовать имена методов которые говорят мне обе вещи: что они создают новый экзэмпляр и что параметр означает.


Классы с единственным экзэмпляром

Некоторые классы имеют только один экзэмпляр. Примерами из системных классов являются \verb|истина|, которая является единственым экзэмпляром класса \verb|Истина|, \verb|лож|, экзэмпляр \verb|Лож|, \verb|пусто|, экзэмпляр \verb|НеопределённыйОбъект|, и \verb|Процэссор|, экзэмпляр \verb|ПланировщикПроцэссора|. Классы \verb|НеопределённыйОбъект|, \verb|Логиче--| и \verb|ПланировщикПроцэссора| переопределяют метод \verb|новый| для предотвращения создания экзэмпляров.


В твоём собственном коде, если у тебя есть класс который должэн иметь только один экзэмпляр, самым простым способом добиться этого завести переменную класса которая содержыт единственный экзэмпляр. Когда кто-нибудь попытается создать новый экзэмпляр после того как создан первый, ты можэш или вызвать ошыбку или возвратить первый экзэмпляр. Например,


класс МойКласс>>новый
  Экзэмпляр пусто? лож? [сам ошыбка: 'Ты можэш использовать
                         только один экзэмпляр МоегоКласса'].
  Экзэмпляр := сам проснойНовый.
  ^Экзэмпляр
класс МойКласс>>новый
  ^Экзэмпляр пусто?
      истина? [Экзэмпляр := сам простойНовый]
      лож? [Экзэмпляр]