Smalltalk по-русски
Advertisement
3.0

Классы и экземпляры[]

Объекты представляют компоненты системы Смолток – числа, структуры данных, процессы, файлы на диске, планировщик процессов, редакторы текста, компиляторы, и приложения. Сообщения представляют взаимодействие между компонентами системы Смолток – арифметические операции, доступ к данным, управляющие структуры, создание файла, редактирование текста, компиляция и использование приложений. Сообщения делают функциональность объекта доступной для других объектов, при этом оставляя реализацию объекта скрытой. Предыдущая глава ввела синтаксис предложения для описания объектов и сообщений, уделяя основное внимание на способах использования сообщений для доступа к функциональности объектов. Данная глава вводит синтаксис для описания методов и классов с точки зрения как данная функциональность реализуется.

Каждый объект системы Смолток это экземпляр какого либо класса. Все экземпляры классы имеют один и тот же интерфейс; класс описывает как выполнять каждую операцию доступную в интерфейсе. Каждая операция описывается в виде метода. Селектор сообщения определяет тип операции которую должен выполнить получатель, таким образом в классе существует один метода для каждого селектора присутствующего в интерфейсе. Когда объекту посылается сообщение, вызывается метода связанный с данным типом сообщения в классе получателя. Класс также описывает какая есть private память у экземпляра.

У каждого класса есть имя которое описывает тип компонента представленного экземплярами данного класса. Имя класса служит для двух основных целей: оно является простейшим способом ссылки на себя, и оно является способом ссылки на класс в предложениях. Т.к. класс это компонент системы Смолток он является объектом. Имя класса автоматически становится именем глобально доступной переменной. Значение данной переменной это объект представляющий класс. Т.к. имя класса это имя глобальной переменной оно должно начинаться с большой буквы.

Новые объекты создаются с помощью посылки сообщения классам. Большинство классов отвечает на унарное сообщение новый созданием нового экземпляра себя. Например,

Упорядоченная совокупность новый.

возвращает новую совокупность которая является экземпляром класса системы Упорядоченная совокупность. Новая Упорядоченная совокупность всегда пустая. Некоторые классы создают экземпляр в ответ на другие сообщения. Например, класс чьи экземпляры представляют время дня это Время; Время отвечает на сообщение сейчас экземпляром представляющим текущее время. Класс чьи экземпляры представляют день года это Дата; Дата отвечает на сообщение сегодня экземпляром представляющим текущий день. Когда создаётся новый экземпляр он автоматически разделяет методы класса который получил сообщение для создания экземпляра.

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

  1. Описание протокола содержит список сообщений в интерфейсе экземпляра. Каждое сообщение сопровождается комментарием описывающим операции которые должен выполнить экземпляр в ответ на сообщение.
  2. Описание реализации показывает как функциональность описанная в протоколе реализуется. Описание реализации даётся в форме личной памяти экземпляра и набора методов которые описывают как экземпляр выполняет свои операции.

Третий способ представления классов это интерактивное окно, называемое браузером системы. Браузер -- это часть интерфейса программы и он используется в работающей системе Смолток. Описание протокола и описание реализации создано для не интерактивных документов как данная книга. Браузер будет рассмотрен подробнее в семнадцатой главе.

Описание протокола[]

Описание протокола это сообщения понимаемые экземпляров данного класса. Каждое сообщение записывает с комментарием о его назначении. Комментарий описывает операции которые будут выполнены при получении сообщения и какое значение будет возвращено. Комментарий описывает почему это делается, а не как операция будет выполнена. Если комментарий не даёт указаний о возвращаемом значении то предполагается что возвращаемое значение это получатель сообщения.

Например, описанием протокола для сообщений Финансовой истории с селектором потратить:на: является:

потратить: количество на: причина запомнить что количество денег, количество, было потрачено на причину.

Сообщения в описании протокола описываются в форме образца сообщения. Образец сообщения содержит селектор сообщения и набор имён аргументов, одно имя для каждого аргумента которое должно иметь сообщение с данным селектором. Например образец сообщения

потратить: количество на: причина

Обозначает сообщения описываемые каждым из следующих трёх предложений.

Домашнее хозяйство потратить: 32.50 на: 'коммунальные услуги'.
Домашнее хозяйство потратить: цена + налог на: 'еда'.
Домашнее хозяйство потратить: 100 на: обычная причина.

Имена аргументов используются в комментарии для ссылки на аргументы. Комментарий в вышеприведённом примере указывает что первый аргумент представляет количество потраченных денег и второй аргумент представляет на что эти деньги были потрачены.

Категории сообщений[]

Сообщения которые выполняют похожие операции объединяются в категории. Категории имеют имя которое обозначает общее поведение сообщений группы. Например, сообщения Финансовой истории объединяются в три категории с именами: запись транзакций, справки и инициализация. Эти категории предназначены для более удобного чтения протокола человеком, они не влияют на работу класса.

Ниже показано полное описание протокола для Финансовой истории:

Протокол Финансовой истории
запись транзакций
получить: количество из: источник запоминает что данное количество денег, количество, было получено из источника.
потратить: количество на: причина запоминает что данное количество денег, количество, было потрачено на причину.
справки
количество наличных запрашивает о текущем количестве наличных денег.
общее поступление из: источник запрашивает общее количество денег поступивших из источника.
общие траты на: причина запрашивает общее количество денег потраченных на причину.
инициализация
инициализироать баланс: количество начать финансовую историю с данным количеством доступных денег.

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

Описание реализации[]

Описание реализации состоит из трёх частей

  1. имя класса
  2. объявление переменных доступных экземпляру
  3. методы используемые экземпляром для ответа на сообщения

Далее приведено полное описание реализации для Финансовой истории. Методы в описании реализации разделены на те же категории что и в описании протокола. В браузере системы категории используются для ирархического доступа к описанию частей класса. Нет специальных знаков которые разделяют различные части описании реализации. Изменения в шрифте и выделении обозначают различные части. В браузере системы эти части представлены независимо и браузер предоставляет редактор для доступа к ним.

имя класса Финансовая история
имена переменных экземпляра количество наличных приход расход
методы экземпляра
запись транзакций
получить: количество из: источник
   приход от: источник пом: (сам общее поступление из: источник) + количество.
   количество наличныхколичество наличных + количество.

потратить: количество на: причина
   расход от: причина пом: (сам общие траты на: причина) + количество.
   количество наличныхколичество наличных - количество.

справки
количество наличных
   количество наличных.

общее поступление из: источник
   (приход содержит ключ: источник)
      истина: [ приход от: источник. ]
      ложь: [ 0. ].


общие траты на: причина
   (расход содержит ключ: причина)
      истина: [ расход от: причина. ]
      ложь: [ 0. ].

инициализация
общие траты на: причина
   (расход содержит ключ: причина)
      истина: [ расход от: причина. ]
      ложь: [ 0. ].

инициализировать баланс: количество
   количество наличныхколичество.
   приходСловарь новый.
   расходСловарь новый.

Данное описание реализации отличается от описания Финансовой истории представленного на форзаце этой книги. Вариант на форзаце содержит дополнительный раздел называемый «методы класса» которые будут объяснены в пятой главе, также там нет методов инициализации показанных здесь.

Определение переменных[]

Методы класса имеют доступ к пяти различным типам переменных. Эти типы различаются областью доступности (их областью видимости) и временем жизни.

Есть два типа собственных переменных доступных только объекту:

  1. Переменные экземпляра – существуют всё время жизни объекта.
  2. Временные переменные – существуют во время определённых действий и доступны только в течении этих действий.

Переменные экземпляра представляют текущее состояние объекта. Временные переменные представляют промежуточное состояние нужное для выполнения некоторых действии. Временные переменные обычно связанны с выполнением метода: они создаются когда приходит сообщение и уничтожаются когда выполнение метода заканчивается.

Другие три типа переменных могут быть доступны более чем одному объекту. Они различаются по области своей доступности.

  1. Переменные класса – разделяются всем экземплярами класса.
  2. Глобальные переменные – разделяются всеми экземплярами всех классов (т.е. всем объектами).
  3. Переменные пула – разделяются экземплярами подмножества классов системы.

Большинство разделяемых переменных системы это либо переменные класса либо глобальные переменные. Большинство глобальных переменных ссылаются на классы системы. Экземпляр Финансовой истории с именем Домашнее хозяйство использовался в нескольких примерах в предыдущих главах. Мы испльзовали Домашнее хозяйство как будто он определён как глобальная переменная. Глобальные переменные используются чтобы ссылаться на объекты не являющиеся часть других объектов.

спомните что имена разделяемых переменных (3-5) начинаются с большой буквы, в то время как имена собственных переменных (1-2) нет. Значение разделяемой переменной не зависит от того в каком экземпляре эта переменная используется. Значения переменных экземпляра и временных переменных зависит от экземпляра использующего метод, то есть от экземпляра который получил сообщение.

Переменные экземпляра[]

Существует два типа переменных экземпляра: именованные и нумерованные. Они различаются способом объявления и способом доступа. Класс может иметь только именованные переменные, только нумерованные или оба типа.

Именованные переменные экземпляра. Описание реализации содержит множество имён для переменных экземпляра которые используют экземпляры класса. Каждый экземпляр имеет одну переменную соответствующую каждому имени переменной экземпляра. Объявление переменных в описании реализации класса Финансовая история определяет три имени переменных экземпляра.

  • расход ссылается на словарь который связывает причины трат с потраченным количеством.
  • приход ссылается на словарь который связывает поступающие суммы с количеством поступивших денег.
  • количество наличных ссылается на число представляющее количество доступных денег.

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

Когда создаётся новый экземпляр при помощи сообщения посланного классу он получает новый набор переменных экземпляра. Переменные экземпляра инициализируются в соответствии с сообщением создания экземпляра. Метод инициализации по умолчанию присваивает каждой переменной экземпляра значение пусто.

Например, чтобы предыдущие примеры сообщений к HouseholdFinances работали нужно выполнить предложение подобное следующему:

Домашнее хозяйствоФинансовая история новый инициализировать баланс: 350.

Финансовая история новый - создаёт новый объект чьи все три переменных ссылаются на пусто. Сообщение новому экземпляру инициализировать баланс: присваивает трём переменным экземпляра более подходящие начальные значения.

Нумерованые переменные экземпляра. Экземпляры некоторых классов могут иметь переменные экземпляра которые не доступны с помощью имени. Они называются нумерованными переменными экземпляра. Вместо ссылки на переменную с помощью имени доступ к нумерованным переменным экземпляра осуществляется при помощи сообщения с целым аргументом, называемым номером. Т.к. нумерование это форма ассоциации два основных сообщения для доступа к переменным имеют те же селекторы что и сообщения к словарям – от: и от:пом:. Например экземпляр Ряда имеет нумерованные переменные. Если имена это экземпляр Ряда то предложение

имена от: 1.

возвратит значение своей первой нумерованной переменной. Предложение

имена от: 4 пом: 'Adele'.

поместит цепь ‘Adele’ как значение четвёртой нумерованной переменной экземпляра объекта имена. Допустимые индексы пробегают значения от единицы до числа нумерованных переменных в данном экземпляре.

Если у экземпляр класса есть нумерованные переменные то его объявление переменных должно включать строку нумерованные переменные экземпляра. Например часть описания реализации класса системы Ряд:

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

Каждый экземпляр класса имеющего нумерованные переменные экземпляра может иметь различное их количество. Все экземпляры Финансовой истории имеют три переменные экземпляра, но экземпляры Ряда могут иметь любое количество переменных экземпляра.

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

имя класса Упорядоченная совокупность
имена переменных экземпляра первый номер последний номер
нумерованные переменные экземпляра

Все экземпляры Упорядоченной совокупности должны иметь две именованные переменные, но один может иметь пять нумерованных переменных, другой 15, другой 18 и т.д.

Именованные переменные экземпляра класса Финансовая история являются собственными в том смысле что доступ к этим переменным контролируются экземпляром. Класс может включать или может не включать сообщения дающие прямой доступ к переменным экземпляра. Нумерованные переменные экземпляра не собственные в данном смысле, т.к. прямой доступ к значениям этих переменных доступен при помощи посылки сообщений с селекторами от: и от:пом:. Т.к. это единственный способ получить доступ к нумерованным переменным он должен быть предоставлен.

Классы с нумерованными переменными экземпляра сознают новые экземпляры при помощи сообщения новый: вместо использования сообщения новый. Аргумент сообщения новый: указывает количество нумерованных переменных.

списокРяд новый: 10.

создаёт Ряд из 10 элементов, каждый из которых сначала ссылается на пусто. Количество нумерованных переменных экземпляра можно определить с помощью сообщения размер. Ответ на сообщение размер

список размер.

для данного примера это целое 10.

Выполнение каждого из следующих предложений в данном порядке:

списокРяд новый: 3.
список от: 1 пом: 'один'.
список от: 2 пом: 'два'.
список от: 3 пом: 'три'.

эквивалентно одному предложению

список#( 'один' 'два' 'три' ).

Разделяемые переменные[]

Переменные которые разделяются более чем одним объектом объединяются в группы называемые пулами. Каждый класс имеет два или более пула чьи переменные могут быть доступны экземплярам. Один пул разделяется всеми классами и содержит глобальные переменные, этот пул называется Смолток. Каждый класс также имеет пул который доступен только его экземплярам и содержит переменные класса.

Помимо этих двух обязательных пулов классу могут быть доступны некоторые другие пулы разделяемые несколькими классами. Например, в системе существуют несколько классов которые представляют текстовую информацию; этим классам нужен доступ к кодам ASCII для знаков которые трудно представлять визуально, таким как перевод строки, табуляция или пробел. Эти числа включены как переменные в пул именуемый TextConstants который разделяется классами реализующими редактирование и показ текста. Если Финансовая история имеет переменную класса с именем SalesTaxRate и разделяет словарь пула с именем FinanicalConstnts объявление должно записываться так:

имя класса Финансовая история
имена переменных экземпляра количество наличных приход расход
имена переменных класса SalesTaxRate
разделяемые словари Финансовые константы

SalesTaxRate это имя переменной класса так что она может быть использована в любом методе класса. С другой стороны Финансовые константы это имя пула, есть переменные в пуле которые могут быть использованы в предложениях.

Чтобы объявить переменную глобальной (известной для всех классов и пользователей системы) имя переменной нужно поместить как ключ в словаре Смолток. Например чтобы сделать глобальной Все истории выполните предложение

Смолток от: #Все истории пом: пусто.

Затем используйте предложение присваивание для задания значения Всем историям.

Методы[]

Метод описывает как объект будет выполнять одну из своих операций. Метод состоит из образца и последовательности предложений отделённых точкой. Пример метода показанный ниже описывает ответ Финансовой истории на сообщение информирующее его о расходовании денег

потратить: количество на: причина
   расход от: причина пом: (сам общие траты на: причина) + количество.
   количество наличныхколичество наличных - количество.

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

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

Имена аргументов[]

Обрезец сообщения был введён выше в данной главе. Образец сообщения содержит селектор сообщения и набор имён аргументов, имя для каждого из аргументов которое должен иметь метод с данным селектором. Образец сообщения совпадает с любым сообщением которое имеет то же селектор. Класс должен иметь только один метод с данным селектором в образце сообщения. Когда сообщение посылается метод с совпадающим образцом сообщения выбирается из класса получателя. Предложения в выбранном методе выполняются одно за другим. После выполнения всех предложений возвращается значение пославшему сообщение.

Имена аргументов в образце метода это имена псевдо переменных которые ссылаются на аргументы действительного сообщения. Если метод показанный выше вызовется при помощи предложения

Домашнее хозяйство потратить: 30.45 на: 'еда'.

имя псевдо переменная количество будет ссылаться на число 30.45 и имя псевдо переменная цель будет ссылаться на цепь ‘еда’ в течении выполнения предложений метода. Если тот же метод будет вызван при помощи предложения:

Домашнее хозяйство потратить: цена + налог на: 'еда'.

цене будет послано сообщение + налог и на возвращённое значение будет ссылаться переменная количество. Если цена ссылается на 100 и налог на 6.5, то значение количество будет равно 106.5.

Возвращаемое значение[]

Метод потратить:на: не определяет какое значение должно быть возвращено. Поэтому, по умолчанию, будет возвращён сам получатель. Когда нужно возвратить другое значение в методе записывается одно или несколько предложений возврата. Можно возвратить значение любого предложения при помощи добавление предшествующей стрелки вверх (↑). Значение переменной можно возвратить так:

количество наличных.

Значение другого сообщение можно вернуть так:

расход от: причина.

Объект литерал можно возвратить так:

0.

Можно вернуть даже значение предложения присваивания:

начальный номер 0.

Сначала происходит присваивание. Затем возвращается новое значение переменной.

Пример использования предложения возврата в реализации метода общие траты на:

общие траты на: причина
   (расход содержит ключ: причина)
      истина: [ расход от: причина. ]
      ложь: [ 0. ].

Данный метод содержит одно условное предложение. Если причина есть в расходах, возвращается соответствующее значение; иначе возвращается ноль.

Псевдо переменная сам[]

Наряду с псевдо переменными используемыми для ссылания на аргументы метода все методы имеют доступ к псевдо переменной с именем сам которая ссылается на получателя сообщения. Например, в методе потратить:на: сообщение общие траты на: посылается получателю сообщения потратить:на:.

потратить: количество на: причина
   расход от: причина пом: (сам общие траты на: причина) + количество.
   количество наличныхколичество наличных - количество.

Во время выполнения этого метода первое что происходит это посылка сообщения общие траты на: к тому же объекту (себе) который получил потратить:на:. Результату этого сообщения посылается сообщение + количество, и результат этого сообщения используется как второй аргумент сообщения от:пом:.

Псевдо переменная сам может быть использована для реализации рекурсивных функций. Например, сообщение факториал понимается целыми числами чтобы вычислить соответствующую функцию. Метод связанным с селектором факториал:

факториал
   сам = 0 истина: [ 1. ].
   сам < 0
      истина: [ сам ошибка: 'factorial invalid'. ]
      ложь: [ сам * (сам - 1) факториал. ].

Получатель это Целое. Первое предложение проверяет не является ли получатель 0 и если это так то возвращает 1. Второе предложение проверяет знак получателя, т.к. если он меньше нуля нужно вызвать сообщение об ошибке (все объекты отвечают на сообщение ошибка: уведомлением о том что произошла ошибка). Если получатель больше нуля, то возвращённым значением будет

сам * (сам - 1) факториал

Значение возвращённое получателем это получатель умноженный на факториал числа на единицу меньшего чем получатель.

Временные переменные[]

Имена аргументов и сам доступны только в течении выполнения метода. В дополнение к псевдо переменным метод может иметь несколько других переменных для использования в течении выполнения. Они называются временными переменными. Временные переменные объявляются между образцом метода и предложениями метода. Объявление временных состоит из набора имён переменных между вертикальными чертами. Метод для селектора потратить:на: можно переписать с использованием временной переменной для запоминания предыдущего расхода.

потратить: количество на: причина
   | предыдущие расходы |
   предыдущие расходысам общие траты на: причина.
   расход от: причина пом: предыдущие расходы + количество.
   количество наличныхколичество наличных - количество.

Значение временной переменной доступно только для предложений метода и уничтожается когда выполнение метода завершается. Все временные переменные изначально ссылаются на пусто.

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

   | список |
   списокРяд новый: 3.
   список от: 1 пом: 'один'.
   список от: 2 пом: 'четыре'.
   список цепь для печати.

Программист выделяет все пять строк – определение и предложения – и запрашивает их выполнение. Переменная список доступна только во время единичного выполнения выделенного текста.

Примитивные методы[]

Когда объект получает сообщение от обычно просто посылает другие сообщения, и где же происходят реальные действия? Объект может при получении сообщения изменить значения своих переменных экземпляра, что естественно оценивается как “что-то произошло”. Но этого не достаточно. Всё поведение системы вызывается сообщениями, однако не все сообщения отвечают при помощи выполнения методов Смолтока. Есть около сотни примитивных методов способ выполнения которых знает виртуальная машина Смолток. Примерами сообщения которые выполняются примитивом является сообщение + к малому целому, сообщение от: к объектам с нумерованными переменными, и сообщение новый: к классам. Когда 3 получает сообщение + 4, она не выполняет метод Смолток. Примитивный метод возвращает 7 как значение сообщения. Полный набор примитивных методов включён в четвёртую часть данной книги, которая описывает виртуальную машину.

Метод который реализован как примитивный начинается с выражения вида

<примитив №>

где № это номер указывающий какой примитивный метод будет использоваться. Если примитив не может завершиться правильно, управление передаётся методу Смолток. За выражением <примитив №> следуют предложения Смолтока которые обрабатывают ошибочную ситуацию.

Сводка терминологии[]

класс – объект который описывает реализацию набора подобных объектов.

экземпляр – один из объектов описываемых классом, он имеет память и отвечает на сообщения.

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

описание протокола – описание класса в терминах протокола сообщений экземпляра.

описание реализации – описание класса в терминах собственных переменных экземпляра и набора методов которые описывают способ выполнения операций.

образец сообщения – селектор сообщения и набор имён аргументов, по одному имени для каждого аргумента которые должно иметь сообщение с данным селектором.

временная переменная – переменная созданная для выполнения специальной задачи и доступная только в течении этого действия.

переменная класса – переменная разделяемая экземплярами одного класса. глобальная переменная – переменная разделяемая всеми экземплярами всех классов.

переменная пула – переменная разделяемая экземплярами набора классов.

Смолток – пул разделяемый всеми классами который содержит все глобальные переменные.

метод – описание процедуры выполнения одной из операций объекта; состоит из образца сообщения, объявления временных переменных и последовательности предложений. Метод вызывается когда сообщение совпадающее с образцом посылается экземпляру класса в котором находится метод.

имя аргумента – имя псевдо переменной доступной только в течении выполнения метода; значение имени аргумента это аргумент сообщения которое выполняет метод.

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

сам – псевдо переменная ссылающаяся на получателя сообщения.

категория сообщения – группа методов в описании класса.

примитивный метод – операция выполняемая напрямую виртуальной машиной Смолтока, не описывается как последовательность предложений на Смолтоке.

Advertisement