Москва, 2006
1. ВВЕДЕНИЕ В СРЕДУ ПРОГРАММИРОВАНИЯ SMALLTALK
ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ. ОСНОВНЫЕ ПОНЯТИЯ ООП
2. СТАНДАРТНЫЕ КЛАССЫ И МЕТОДЫ
ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ. КЛАССЫ
3. ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ SMALLTALK
ЗАДАНИЯ К ЛАБОРАТОРНЫМ РАБОТАМ
Основной конструкцией в ООП является объект. В качестве объектов могут выступать программистские абстракции (числа, символы, файлы, и т.д.) или сущности моделируемой предметной области и их взаимосвязь. Объекты взаимодействуют друг с другом, посылая и принимая сообщения.
Объект обладает собственной памятью для хранения информации и набором методов - операций для манипулирования этой информацией. Для активизации метода объекту посылается сообщение - аналог обращения к функции в традиционных языках программирования. В каждом сообщении должен быть указан адресат - объект, к которому посылается сообщение, имя сообщения и, возможно, несколько объектов-параметров с которыми может манипулировать метод. Программа в системе ООП, таким образом, - последовательность сообщений к различным объектам.
Таблица 1. Некоторые примеры сообщений и их результатов
Сообщение |
Описание |
1 + 2 |
Бинарное сообщение |
'привет' вПозиции: 5 ('привет' inPos: 5) |
Ключевое сообщение Объект – адресат: 'привет' (Cтрока) Имя сообщения: вПозиции: Объект – параметр: 5 (МалоеЦелое) Результат: (Символ) |
12 факториал (12 factorial) |
Унарное сообщение Объект – адресат: 12 (МалоеЦелое) Имя сообщения: факториал Объект – параметр: нет Результат: (БольшоеЦелое) |
(5 между:3 и:7) (5 in:3 and:7) |
Ключевое сообщение Объект – адресат: 5 (МалоеЦелое) Имя сообщения: между: и: Объект – параметр: 3,7 (МалоеЦелое) Результат: Истина |
Система Смолток - это интерактивная многооконная среда программирования. Запуск системы осуществляется командой s.exe. После заставки на экране появляется одно или более окон, которые могут перекрываться. Каждое окно имеет заголовок. Основное окно, которое обычно является рабочим пространством, имеет заголовок «Информация системы». Для того, чтобы работать с выбранным окном, необходимо поместить указатель мыши на это окно и нажать левую кнопку мыши. Если мышь отсутствует, то для выбора окна используется функциональная клавиша F9. Выбранное окно показывается инвертированием его заголовка и называется Активным окном.
Каждое окно имеет систему меню. В зависимости от положения стрелки при нажатии правой кнопки мыши появляются различных меню. Если стрелка указывает на заголовок активного окна, вызывается следующие меню:
цвет |
изменить цвета текста и фона окна |
сжать |
Минимизировать размеры окна |
цикл |
перейти к следующему открытому окну |
контур |
изменить размеры окна |
сдвиг |
передвинуть окно |
закрыть |
закрыть окно |
(Для окна «Информация системы» пункты «закрыть» и «сжать» отсутствуют.)
Выбор осуществляется нажатием правой кнопки мыши или клавишей '+'. Еще один способ вызова данного меню - клавиша INS.
Если стрелку поместить внутри окна и нажать правую кнопку мыши (или клавишу DEL), появляется меню рамки:
восстановить |
Восстановить текст |
установить |
|
скопировать |
Данные функции осуществляют редактирование выделенного текста |
вырезать |
|
вставить |
|
показать |
Вычислить выделенное выражение и показать результат |
выполнить |
Выполнить выделенное выражение |
сохранить |
Сохранить (откомпилировать) текст |
сохранить в |
|
след. Меню |
печатать |
поиск |
глоб. Поиск |
поиск назад |
заменить все |
снова |
(Для окна «Информация системы» пункты «сохранить в» и «установить» отсутствуют.)
Если в активном окне присутствует несколько рамок (например, окно «Просмотр диска»), то для каждой рамки при нажатии правой кнопки мыши или клавиши DEL появляется свое меню.
Нажатие правой кнопкой мыши вне какого-либо окна (поместить стрелку вне какого-либо окна и нажать DEL или INS), вызывает появление системного меню:
выход в DOS |
|
память/скорость |
оптимизация по коду или скорости |
выход из системы |
|
просмотр диска |
|
вызов окна «Просмотр диска» |
|
рабочее окно |
вызов окна «Рабочее окно» |
просмотр классов |
вызов окна «Просмотр классов» |
восстановить экран |
|
сохранение образа |
сохранение текущего состояния экрана |
демонстрация |
запуск демонстрации некоторых графических возможностей |
Выбор пункта в любом меню производится клавишей '+' или левой кнопкой мыши. Выход из меню осуществляется перемещением курсора за пределы рамки меню и нажатием любой кнопки мыши или клавиши '+'.
Действие |
Клавиатура |
Мышь |
смена окна |
F9 |
указать стрелкой нужное окно (нужную рамку) и нажать левую кнопку мыши |
смена рамки |
F10 |
|
меню окна |
Ins |
поместить стрелку внутрь заголовка окна и нажать правую кнопку мыши |
меню рамки |
Del |
поместить стрелку внутрь окна и нажать правую кнопку мыши |
выбор |
+ |
поместить стрелку на начало текста, нажать левую кнопку мыши, не отпуская кнопку переместить мышь в конец текста |
конец выбора |
- |
|
выбор в меню |
+ |
левая кнопка мыши |
сдвиг вниз |
PgUp |
поместить стрелку на соответствующий край окна и нажать правую кнопку мыши, не отпуская кнопку перемещать мышь в нужную сторону. |
сдвиг вверх |
PgDn |
|
сдвиг вправо |
Home |
|
сдвиг влево |
End |
Сделайте активным окно «Информация системы». Внутри каждого окна, помимо стрелки, имеется курсор. Наберите команду 2+3. Вывод текста осуществляется в том месте, где расположен курсор. Заметим, что если стрелка находится за границей активного окна, то при нажатие любой клавиши (кроме специальных клавиш) раздается предупреждающий сигнал. Поэтому следите за положением стрелки. Она должна всегда находится в пределах активного окна.
Поместите стрелку на начало введенной строки (2+3) и нажмите клавишу '+' на правой клавиатуре или левую кнопку мыши. Курсор переместится на начало строки. Затем поместите стрелку в конец строки и нажмите клавишу '-' на правой клавиатуре. Произойдет выделение (выбор, инвертирование) текста. С помощью мыши выделение производится следующим образом: стрелка помещается на начало текста, а затем нажимается левая кнопка мыши и, не отпуская кнопки, мышь передвигается в конец текста. Как только кнопка отпускается, выбор заканчивается. Над выделенным текстом можно производить операции редактирования, запускать на выполнение и т.д.
Упражнение 1. Сделайте активным окно «Рабочее окно». Наберите выражение 3 + 4 и выделите его. Войдите в меню рамки и выберите пункт «показать».
Упражнение 2. Выполните с помощью пункта меню рамки «выполнить» следующую программу:
| f |
f:=200.
5 разПовторить: [ f:=f+1]
^f
Упражнение 3. Запустите программу демонстрации некоторых графических возможностей системы:
а) выполнив команду Демонстрация запустить;
б) с помощью системного меню.
Замечание 1. Если при компиляции будет найдена ошибка и появится окно, которое сообщает о допущенной ошибке, то следует удалить это окно (с помощью меню окна «закрыть»). Удаление неверно набранного текста осуществляется его выделением с последующим нажатием клавиши BACKSPACE).
Замечание 2. Обратите внимание на то, что система чувствительна к регистру вводимых символов.
Объект обладает свойствами, поведением и состоянием. Ему можно присвоить имя. Объекты с одинаковыми свойствами и поведением объединены в классы, экземпляры которых отличаются друг от друга именами и состояниями. Каждый объект входит в один класс и называется экземпляром класса.
Упражнение. Выполните следующие выражения («показать»):
#( 1 2 3 4 5 'вышел зайчик погулять') класс
1+2 класс
'Институт' класс
(5/9) класс
Объекты из одного класса распознают одни и те же сообщения и имеют одинаковую структуру собственной памяти. Объект имеет собственную память - переменные экземпляра, где хранится информация о его свойствах и состоянии. Доступ к указанной информации имеет только сам объект.
С каждым объектом связан набор (протокол) сообщений, которые он понимает. Всякому сообщению из протокола соответствует реализующая его процедура, называемая методом. Метод определяет реакцию объекта на данное сообщение, т.е. его поведение. Он состоит из операций над своими переменными экземплярами и из посылок сообщений другим объектам. В конечном счете, объект возвращает ответ на посланное ему сообщение. Поскольку все объекты одного класса обладают одинаковым набором методов, последний хранится в одном месте - в самом классе.
У каждого класса существует два типа методов:
· методы класса;
· методы экземпляра.
Методы класса используются, когда необходимо произвести какие-либо действия с целым классом, например, добавить к классу новый экземпляр. Сообщения к экземплярам инициализируют методы, оперирующие с конкретными экземплярами данного класса.
а) Глобальные переменные
В системе есть каталог, содержащий все глобальные переменные программной среды. Он имеет имя Смолток и сам является глобальной переменной. Для определения новой глобальной переменной необходимо вычислить следующее выражение:
Смолток вПозиции: #<имя> разместить: нуль
Имя глобальной переменной начинается с прописной буквы. Символ «#» используется в языке для определения системного имени. Значение глобальной переменной можно изменить, присвоив ей новое значение.
Упражнение. Введем новую глобальную переменную НовыйГод. (вычислите следующее выражение, используя пункт 'выполнить')
Смолток вПозиции: #НовыйГод разместить: нуль.
(вычислите следующее выражение, используя пункт 'показать')
НовыйГод:= '31 Декабря' .
Эти две строки можно заменить одной:
Смолток вПозиции: #НовыйГод разместить: '31 Декабря'
Текущее значение определенной глобальной переменной <имя> можно напечатать, выполнив следующее выражение (пункт 'показать'):
<имя>
Существует еще один способ ввода новых глобальных переменных. Для этого выполним следующее выражение (пункт 'показать'):
Календарь
На экране появится окно, в котором будут 2 сообщения:
«'Календарь' не определено» и
«определить ' Календарь' как глобальную».
Выберите пункт 2 и выполните, используя 'показать', следующее выражение:
Календарь := Дата календарьНаМесяц: #окт год:1994.
б) Временные переменные
Выполните следующие выражения ('показать'):
| расстояние скорость время |
расстояние:= 200.
скорость:= 5.
время:= расстояние/скорость.
^время
в) Псевдопеременные
Системные псевдопеременные:
· нуль ссылка на пустой объект
· сам, супер используются в качестве адресатов при обращении из метода какого-либо объекта к самому себе (сам) либо к суперклассу (супер).
Кроме того, в системе существуют еще две псевдопеременные, позволяющие организовывать условные выражения:
· истина, ложь ссылки на объекты, представляющие «истину» и «ложь»
Применение данных системных псевдопеременных в левой части оператора присваивания запрещено.
а) Сравнение объектов
Выполните последовательно следующие выражения ('показать'):
3 > 4
#(1 2 3 )= #(1 2 3)
'привет' >'пока'
5=2+3
5=(3+2)
$a этоВВерхнемРегистре
('привет' вОбратномПорядке вПозиции: 2) этоГласная
7 нечетный или: 10 четный
б) Условные выражения
Условная конструкция имеют вид:
<условие>
если условие истинно: [ <блок выражений> ]
если условие ложно: [ <блок выражений> ]
На языке ООП эта конструкция записывается таким образом:
<объект-адресат класса Истина или Ложь>
еслиИстина: <объект-параметр>
еслиЛожь: <объект-параметр>
В данном случае <объект-параметр> представляет из себя блок сообщений.
Блок-сообщение - это группа сообщений, заключенная в квадратные скобки.
Возможны и следующие конструкции:
<условие> еслиИстина: [ <группа сообщений> ].
<условие> еслиЛожь: [ <группа сообщений> ].
Упражнение. Выполните следующую программу ('показать'):
| максимум a b |
a:= 5 вКвадрате.
b:= 4 факториал.
a>b еслиИстина: [максимум:= a] еслиЛожь: [максимум:=
b].
^максимум
<число> разПовторить: [ блок сообщений ] |
Повторить блок заданное <число> раз |
[блок условия] покаЛожь: [ блок сообщений ] |
Пока условие ложно выполняется сообщения |
[блок условия] покаИстина: [ блок сообщений ] |
Пока условие истинно выполняются сообщения |
<число1> до:<число2> через:<шаг> выполнить: [ :<переменная> | блок сообщений ] |
Выполнять блок сообщений, пока значение <переменной>, изменяющее свое значение с заданным шагом принадлежит промежутку (число1,число2) |
<объект> выполнить: [ :<переменная> | блок сообщений ] |
Значение <переменной> присваивается последовательно элементам <объект> |
<объект> выбрать: [ :<переменная> | <условие> ] |
Изменяет <объект>, удалая элементы,не удовлетворяющие условию |
<объект> исключить: [ :<переменная> | <условие> ] |
Изменяет <объект>, удалая элементы, удовлетворяющие условию |
<объект> собрать: [:<переменная> | сообщение] |
Заменяет каждый элемент <объекта> на результат выполненого сообщения |
а) Простые циклы
Упражнения
Выполните программу ('показать'):
| индекс факториалы временная |
факториалы:= #( 3 4 5 6 ).
индекс:= 1.
факториалы размер разПовторить:
[ временная := факториалы вПозиции: индекс.
факториалы вПозиции: индекс
разместить: (временная факториал).
индекс:=индекс+1. ].
^факториалы
Выполните программу ('выполнить')
«нарисовать несколько многогранников»
| стороны |
стороны:=3.
[стороны <= 6 ] покаИстина:
[ стороны разПовторить: [Черепашка переместитьНа:60; повернутьНа:
360 //стороны ].
стороны := стороны + 1].
б) Простые итерации
Упражнение. Выполните данную программу ('выполнить'). Обратите внимание на отсутствие параметра <шаг>. По умолчанию шаг равен 1.
| f b |
1 до: 6 выполнить: [:f | b:= f факториал.
СистемнаяИнформация поместитьВсеПоследующие: b печатноеИмя; символВК.].
в) Сообщение 'выполнить'
Пример обработки текста:
«посчитать количество запятых в тексте»
| зпт |
зпт:=0.
'ручка, компьютер, часы, телефон, мяч' выполнить: [ :символ | символ = $, еслиИстина:
[ зпт:= зпт + 1 ] ].
^зпт
Пример вычисления суммы арифметической прогрессии:
сумма
| s |
s:=0.
сам выполнить: [:i| s:=s+i ].
^s
г) Сообщения 'выбрать', 'исключить', 'собрать'
Упражнение. Выполните последовательно данные сообщения ('показать')
#(1 2 3 4 5 6 7 8 9) выбрать: [ :x | x факториал >= (x*x*x*x) ]
'привет' выбрать: [ :x | x:=$п]
#(1 2 3 4 5 6 7 8 9) исключить: [ :x | x факториал >= (x*x*x*x) ]
#(1 2 3 4 5 6 7 8 9) собрать: [ :x | x факториал >= (x*x*x*x) ]
#(1 2 13 7 10) собрать: [ :x | x*x ]
'Общаясь с дураком, не оберешься срама...' собрать: [:x | x вВерхнемРегистре]
Пример работы с файлами:
«скопировать дисковый файл FILE.TXT в FILE.BAK»
| ввод вывод |
ввод:= Файл полноеИмя: 'FILE.TXT '.
вывод:=Файл полноеИмя: 'FILE.BAK'.
[ввод вКонце] покаЛожь: [ вывод поместитьСледующий: ввод следующий
].
ввод закрыть.
вывод закрыть.
Пример работы с внутренними объектами:
«Вычислить несколько факториалов»
|ввод вывод|
ввод := ПотокЧтения на: #( 1 5 10 20 ).
вывод := ПотокЗаписи на: Массив новыйЭкземпляр.
[ввод вКонце] покаЛожь: [вывод поместитьСледующий: ввод следующий
факториал].
^вывод содержимое
Замечание: Язык Смолток поддерживает только символьные (текстовые) файлы, поэтому, прежде чем записать в файл число, его необходимо перевести в символьное представление.
Существующие классы анализируются и редактируются путем использования Системного генератора путей - окна «Просмотр классов». Используя это окно можно добавлять новые классы и новые методы. Окно состоит из 3-х частей.
В левой верхней части находится список всех существующих классов. Меню данной рамки представляет следующие возможности:
· вывести в файл - выводит в файл с расширением CLS отмеченный класс со всеми его методами и подклассами;
· обновить систему;
· скрыть/показать - если после имени класса стоит «...», это означает, что данный класс имеет подклассы. Данная команда показывает/скрывает подклассы;
· просмотр класса - вызывает окно «Просмотр класса» для выбранного класса;
· новый класс - добавляет новый подкласс к выбранному классу.
В правой верхней части находится список методов класса или экземпляра класса, который рассматривается в данный момент. Меню данной рамки предоставляет следующие возможности:
· удалить - удалить выбранный метод;
· новый метод - создать новый метод;
· отправители - показываются методы и классы, использующие данный метод;
· получатели - показываются все классы, которым можно послать аналогичное сообщение.
Нижняя рамка содержит текст выбранного метода. Этот текст можно редактировать. Чтобы изменения были внесены в систему, необходимо записать отредактированный текст. Если в правом окне не выбран ни один метод, то нижнее окно содержит определение выбранного класса, которое тоже можно отредактировать.
Чтобы создать объект, классу посылается сообщение о создании нового экземпляра. Класс создает экземпляр с присущей всем объектам этого класса структурой - набором переменных экземпляра. Если нужно, он их инициализирует и выдает созданный экземпляр в качестве ответа на сообщение.
Например:
x:= Массив новыйЭкземпляр: 10.
(создается новый объект, с именем x, класса Массив, размера 10)
Упражнение. Выполните следующие выражения ('показать'):
Дата сегодня
Массив новыйЭкземпляр
Массив новыйЭкземпляр: 5
Для того, чтобы обратиться к нужному методу экземпляра класса, необходимо, чтобы уже существовал экземпляр класса.
Упражнение. Выполните следующее выражение ('выполнить')
ДемоКласс запустить.
Компилятор выдает ошибку, т.к. здесь сообщение посылает класс, а в протоколе сообщений класса такого метода нет. Метод 'запустить' находится в протоколе сообщений экземпляра класса. Поэтому необходимо сначала создать экземпляр класса.
Упражнение. Выполните следующее выражение ('выполнить')
ДемоКласс новыйЭкземпляр запустить.
Возможно создание нового экземпляра в результате выполнения некоторых сообщений. Например:
'Привет,',' Ольга'
(создается новый экземпляр класса «Строка», имеющий значение 'Привет, Ольга' )
1 / 2
(объект-адресат и объект-параметр экземпляры класса «Целое», а результат - экземпляр класса «Дробь»)
1 > 2
(результат - экземпляр класса «Ложь»)
Классы в Смолтоке организованы иерархически в виде дерева. Каждый класс имеет одного предка, называемого суперклассом. Класс может иметь несколько потомков, называемых подклассами. Всякий класс наследует переменные экземпляра и методы своего суперкласса. Кроме того, он может содержать новые переменные экземпляра и методы, а также может переопределять унаследованные.
Еще одно важное свойство ООП - полиморфизм. Одно и то же сообщение может посылаться разным объектам, и понимают они его каждый по-своему. Это увеличивает наглядность программ, поскольку не нужно беспокоиться о случайном совпадении имен сообщений, как это имеет место с именами функций в традиционных языках.
Знание иерархии классов важно для понимания процесса выдачи ответа на сообщение. При получении сообщения объект ищет в своем классе метод с именем, совпадающим с именем сообщения. Если такого метода нет, он ищется в списке методов суперкласса и так далее. Когда метод обнаружен, он выполняется и выдает ответ. Если нигде, вплоть до корня дерева, метод не будет обнаружен, то сгенерируется сообщение об ошибке.
Упражнение. Откройте окно «Просмотр классов» и найдите класс с именем «Дом». Изучите класс «Дом» и выполните следующую программу («выполнить»):
| собака человек |
собака := Собака новыйПерсонаж имя: 'Рекс'.
человек:= Человек новыйПерсонаж имя: 'Алексанрд'; пол: 'муж'.
человек говори: ('Здравствуйте. Я ',( человек имя),'!').
собака говори: 'я собака'.
собака голос.
Первая строка программы создает новый экземпляр класса Собака и сразу присваивает имя этой собаке - Рекс.
Найдите в окне «Просмотр класса» класс «Собака». В протоколе сообщений класса «Собака» нет метода «новыйПерсонаж». Поэтому компилятор просматривает протокол сообщений суперкласса («Дом»).
Обратите внимание на протокол сообщений класса «Дом». Метод класса с именем «новыйПерсонаж» реализован следующим образом:
новыйПерсонаж «имя метода»
^ сам новыйЭкземпляр.
Псевдопеременная «сам» имеет значение объекта-адресата (в данном случае это класс «Собака» ). Метод новыйЭкземпляр не реализован в данном классе, поэтому компилятор ищет реализацию данного метода в суперклассе (Объект).
Аналогичный процесс происходит при поиске методов 'имя''имя:'.
Рассмотрим, что происходит, когда выполняется строка
собака говори: ' я собака'
Протокол сообщений экземпляра класса Собака содержит сообщение 'говори:'. Данный метод реализован следующим образом:
говори: строка
«но собака умеет только лаять»
супер говори: 'Гаф, Гаф, Гаф'.
Псевдопеременная «супер» имеет значение объекта - адресата, но в отличие от псевдопеременной «сам», поиск этого метода начинается не в данном классе, а сразу в его супер-классе (иначе программа зациклилась бы). Метод «голос» реализован также с использованием псевдопеременной «супер».
Рассмотрим программу
| максимум a b |
a:= 5 вКвадрате.
b:= 4 факториал.
a>b еслиИстина: [максимум:= a] еслиЛожь: [максимум:=
b].
^максимум
Создадим на основе данной программы метод, с именем 'макс'. На языке Смолток создание программы происходит в два этапа: описание внешней спецификации и реализация классов и методов.
1 Этап. Внешняя спецификация. Необходимо решить, каким образом будет посылаться сообщение, т.е. ответить на вопросы:
Что будет являться объектом - адресатом?
Что будет являться объектом - параметром?
Что будет являеться результат?
а) объект-адресат - это целое число (Следовательно, данный метод будет принадлежать классу Целыхчисел );
б) объект-параметр - тоже целое число;
в) результат - это тоже целое число.
Таким образом, сообщение будет выглядеть следующим образом:
<экзЦелоеЧислоМакс>: = <экзЦелоеЧислоA> макс: <экзЦелоеЧислоB>
2 Этап. Реализация. Любой метод имеет следующий вид:
имяСообщения
«комментарии»
| временные переменные |
выражения
В нашем случае:
макс: экзЦелое "имя метода с параметром"
«вычисление максимума( a^2 , b!)»
| a b максимум|
a:= сам вКвадрате. "псевдопеременная 'сам'- значение объекта-адресата"
b:= экзЦелое факториал.
a>b
еслиИстина: [максимум:= a]
еслиЛожь: [максимум:= b].
^максимум
Добавим данный метод в класс Целое (суперКласс - Величина): откроем окно «Просмотр классов», выберем класс Целое и добавим в него новый метод. Далее необходимо в меню рамки выбрать команду «сохранить». Теперь можно воспользоваться новым методом:
5 макс: 4
Рекурсия в ООП - это основной механизм реализации итерационных процедур. Именно на рекурсии основаны все циклические конструкции языка.
В качестве примера рассмотрим программу для решения известной головоломки «Ханойские башни». Имеется 3 штырька. На штырьке #1 расположены кольца разного диаметра в порядке убывания их размера снизу вверх. Требуется переложить кольца со штырька #1 на штырек #2, пользуясь штырьком #3 как промежуточным, таким образом, чтобы кольца на штырьке #2 располагались в порядке убывания их диаметра и чтобы в процессе перекладывания кольцо большего диаметра никогда не накладывалось на кольцо меньшего диаметра.
1 Этап. Внешняя спецификация.
а) объект-адресат - это целое число - количество колец. Следовательно, данный метод будет принадлежать классу Целое.
б) объекты-параметры - символы '1','2','3' (информация: с какого штырька на какой нужно переложить кольцо и какой использовать как дополнительный)
в) результат - надписи на экране о последовательности выполнения данной задачи.
Следовательно, вызов метода будет осуществляться, например, следующим образом:
10 ханойC: '1' на: '2' через: '3'
2 Этап. Реализация метода ханойС: x на: y через: z.
Данная задача решается рекурсивно.
а) Базис. Если число колес равно 1, то нужно просто переложить это кольцо c х на y.
б) Если число колес равно К, то нужно переложить со штырька х на штырек z K-1 колец, а затем переложить самое большое K-е кольцо на y и переложить все остальные K-1 колец на y
ханойС: x на: y через: z
«головоломка 'Ханойские башни'»
сам = 1
еслиИстина: [ СистемнаяИнформация
поместитьВсеПоследующие:
'Переложить со штырька ',x,' на штырек ',y;
символВК. ]
еслиЛожь: [ (сам - 1) ханойС: x на: z через: y.
СистемнаяИнформация поместитьВсеПоследующие:
'Переложить со штырька ',x,' на штырек ',y;
символВК.
(сам - 1) ханойС: z на: y через: x
]
Упражнение 1. Вставьте полученный метод в класс Целое и выполните программу для числа колец равного 2,3,10:
10 ханойС: '1' на: '2' через: '3'
Упражнение 2. Добавьте следующий метод к классу Дробь:
дробнаяЧасть
«Выдать адресат минус его целая часть»
^(сам - сам усеченный)
Выполните следующие выражения ('показать'):
(22/7) дробнаяЧасть
Экземпляры класса «Словарь» представляют собой множество пар «ключ-значение». Сами элементы, т.е. пары, являются экземплярами класса «ПараКлючЗначение» (подкласс класса «Величина»).
Создание экземпляра класса «ПараКлючЗначение» осуществляется посылкой сообщения ключ: значение: или сообщения ключ:. Во втором случае значение, соответствующее данному ключу будет иметь значение нуль.
Экземпляр класса «ПараКлючЗначение» имеет две именованные переменные - значение и ключ. Все операции сравнения, определения максимума и минимума реализованы для ключа (а не для значения). То есть, в паре ключ-значение главную и решающую роль играет ключ.
Протокол методов экземпляра класса «Словарь»:
доступ
вПозиции: ключ (результатом является значение, которое соответствует данному ключу. Если ключ отсутствует в словаре выдается сообщение об шибке)
вПозиции: ключ еслиОтсутствует: блок (результатом является значение, которое соответствует данному ключу. Если ключ отсутствует в словаре, выполняется заданный блок)
добавление пары в словарь
вПозиции: ключ разместить: объект
проверка словаря
включаетКлюч: ключ
включаетПару: экзПараКлючЗначение
удаление пары из словаря
удалитьКлюч: ключ
удалитьПару: пара
Например, создадим телефонную книжку. Введем глобальную переменную ТелефоннаяКнижка.
ТелефоннаяКнижка:= Словарь новыйЭкземпляр.
Теперь можно ввести данные:
ТелефоннаяКнижка вПозиции: 'Иванов Л.Ю.' разместить: '12-12';
вПозиции: 'Петров Д.П.' разместить: '55-33';
вПозиции: 'Сидоров К.С.' разместить: '2-12-00'.
Созданную книжку можно дополнять и исправлять.
ТелефоннаяКнижка вПозиции: 'Кузнецов К.Х.' разместить: '905-78'.
Можно просмотреть все данные, записанные в книжке
ТелефоннаяКнижка открытьИнспектор
Открывается окно, которое называется инспектором. Данное окно разделено на две части. В левой части расположены все ключи, введенные в словарь. Выбирая в левой части ключ (в данном случае фамилию) - в правой отображается значение, которое соответствует данному ключу (телефон).
Сообщение открытьИнспектор можно посылать любому объекту. Результат выполнения данного сообщения будет окно «Инспектор», в котором слева располагаются все переменные экземпляра, справа значение выбранной переменной.
В Смолтоке существует 2 типа объектов:
· объекты с поименованными переменными (переменные с именами);
· объекты с индексируемыми переменными (состоит из N объектов, при описании класса, которому принадлежит такой объект, указывается только 1 именованная переменная, остальные N-1 индексируются и доступ к ним осуществляется посылкой сообщения вПозиции: индекс, а не указанием имен).
Объекты с индексируемыми переменными также могут иметь поименованные переменные экземпляра.
Набор - это группа связанных между собой объектов. Классы наборов определяют различные структуры данных для хранения произвольных объектов.
Рис.1. Основные подклассы класса Набор
Создание экземпляров осуществляется посылкой сообщения с: экзОбъект (результат - создание набора с одним элементом равным экзОбъект). Данный метод описан в протоколе методов класса Набор и наследуется всеми его подклассами. Возможно создание набора с 2, 3 или 4 элементами. Для этого существуют следующие методы:
c:экз1 с: экз2 - создание набора с 2 элементами;
c:экз1 с:экз2 с:экз3 - создание набора с 3 элементами;
c:экз1 c:экз2 c:экз3 с:экз4 - набор с 4 элементами.
Наборы поддерживают четыре категории сообщений для доступа к элементам:
сообщения для добавления новых элементов
· добавить: экзОбъект
· добавитьВсе: экзНабор
сообщения для удаления элементов
· удалить: экзОбъект (если экзОбъект отсутствует, то выдается сообщение об ошибке)
· удалить: экзОбъект еслиОтсутствует: блок (удаляется экзОбъект; если такой элемент отсутствует, то выполняется блок)
· удалитьВсе: экзНабор (удаляются все элементы, содержащиеся в заданном наборе)
сообщения для проверки вхождения элементов
· включает: экзОбъект (истина, если приемник содержит экзОбъект, ложь в противном случае)
· числоВхождений: экзОбъект (0, если экзОбъект отсутствует)
сообщения для подсчета элементов
· непустой (истина, если размер>0, ложь в противном случае)
· этоПустой (истина, если количество элементов набора равно нулю)
· выполнить: блок (для каждого элемента набора выполнить заданный блок с этим элементом в качестве аргумента)
· выбрать: блок (для каждого элемента приемника выполнить заданный блок. Результат - новый набор, содержащий те элементы, с которыми блок истинен)
· исключить: блок (результат - новый набор, содержащий те элементы приемника, с которыми блок имеет значение ложь)
· обнаружить: блок (выдать первый элемент приемника, при котором заданный блок выполняется со значением истина. Если такого элемента нет, то выдается ошибка)
· обнаружить: первыйБлок еслиНет: второйБлок (выдать первый элемент приемника, при котором заданный первый блок выполняется со значением истина. Если такой элемент не найден, выполнить второй блок)
· собрать: блок (выдать новый набор, содержащий в качестве элементов результаты выполнения блока)
сообщения для преобразования
· какМассив
· какНаборСДублями (дубли сохраняются)
· какНаборБезДублей (дубли удаляются)
· какУпорядоченныйНабор
· какОтсортированныйНабор (каждый элемент меньше либо равен последующего)
· какОтсортированныйНабор: блок (блок определяет закон упорядочивания)
Класс «ИндексированныйНабор» и его подклассы
Данный класс представляет собой группу, элементы которой имееют фиксированный порядок внешних ключей индентификации элементов в виде целочисленных индексов. Это абстрактный класс для хранения общих методов своих подклассов и поэтому он не создает своих экземпляров.
Общие методы для подклассов класса ИндексированныйНабор:
· , экзИндекНабор - конкатенация, сцепление двух наборов;
· = экзИндекНабор - проверка на равенство двух наборов;
· вЗаданыеПозиции: экзНабор разместить: объект - экзНабор определяет позиции, в которых в заданном наборе нужно разместить объект;
· вОбратномПорядке - результатом является новый набор, в котором элементы расположены в обратном порядке;
· выполнитьВОбратномПорядке: блок - выполняется данный блок для всех элементов набора, но элементы перебираются в обратном порядке;
· найтиПервый: блок
· найтиПоследний: блок - результатом является первый (последний) индекс набора, для которого результат блока - истина
Определены также несколько методов для замены некоторых элементов набора на другие и для нахождения индекса данного объекта, если он присутствует в заданном наборе.
Класс НаборФиксированнойДлины является подклассом класса ИндексированныйНабор. Это абстрактный класс, объединяющий классы Массив, Строка, Интервал. Подклассы представляют наборы с фиксированным диапазоном целых индексов в качестве внешних ключей.
Так как они имеют фиксированный размер, они не отвечают на сообщения добавить:удалить:. При посылке этих сообщений экземпляру подкласса класса НаборФиксированнойДлины появляется сообщение об ошибке.
Для создания экземпляра можно использовать сообщения: новыйЭкземпляр, новыйЭкземпляр: экзЦелое. Результат выполнения этих сообщения - создание пустого набора (в первом случае) или набора длины экзЦелое, каждый элемент которого равен псевдопеременной нуль (второй случай).
Например:
Строка с: $O c: $k. «В результате выполнения данного выражения создается строка 'Ok'»
Массив новыйЭкземпляр: 2 «Результат - #(нуль нуль)»
Элементами класса «Массив» могут быть любые объекты. Элементами класса «Строка» - символы.
Для класса «Строка» определены следующие методы:
· <, <=, =, >, = > - сравнение двух строк (не зависит от регистра)
· равно: стр (равна: стр) - сравнение двух строк на равенство в зависимости от регистра
· убратьПробелы, вВерхнемРегистре, вНижнемРегистре
· какДата, какЦелое
Класс «Интервал» представляет собой конечную арифметическую прогрессию. Его элементы могут быть любым числом: целым, вещественным или дробью.
Для создания экземпляра этого класса используется сообщения от: до: от: до: через:. Класс «Число» также имеет несколько коротких сообщений для создания новых интервалов - до:до:через:.
Например, сообщения
1/2 до: 1 через: 1/8 «(сообщение посылается дроби 1/2)»
Интервал от:1/2 до: 1 через: 1/8 «(сообщение посылается классу Интервал)»
представляют интервал (1/2 5/8 3/4 7/8 1)
Хотя экземпляр класса «Интервал» содержит все числа из заданного интервала с заданным приращением, хранятся только три переменных экземпляра - начало, конец и приращение. Элементы интервала восстанавливаются лишь при обращении к ним.
Класс «УпорядоченныйНабор». Экземпляры этого класса упорядочены той последовательностью действий, в которой объекты добавляются или удаляются. Данный набор похож на динамические массивы, но они могут расширяться в обе стороны. Экземпляр класса «УпорядоченныйНабор» может работать как стек или очередь (см. Табл.1)
Таблица 1
Типичная терминология |
Сообщение для класса УпорядоченныйНабор |
СТЕК (первым пришел - последним вышел) |
|
поместить в стек |
добавитьПоследним: объект |
вытолкнуть |
удалитьПоследний |
вершина |
последний |
пустой |
этоПустой |
ОЧЕРЕДЬ (первым пришел - первым ушел) |
|
добавить |
добавитьПоследним: объект |
удалить |
удалитьПервый |
начало |
первый |
пустой |
этоПустой |
В данном классе описаны несколько методов по добавлению элемента в набор. Есть возможность добавить новый элемент в начало набора, в конец, перед заданным элементов, после заданного элемента.
Класс ОтсортированныйНабор: элементы этого класса упорядочены в соответствии с так называемым блоком сортировки, имеющим два аргумента. Этот блок используется для определения, правильно ли отсортированы два элемента по отношению друг к другу.
Так как позиция каждого элемента указана в блоке сортировки, сообщения типа добавитьПоследним: запрещены. Однако сообщение добавить: вставляет заданный объект в соответствующую позицию, указанную блоком сортировки.
Если при создании нового экземпляра класса ОтсортированныйНабор не указывается блок сортировки, то по умолчанию используется блок: [:a :b| a<=b ]
Есть несколько способов создания нового экземпляра (сообщения, посылаемые классу)
новыйЭкземпляр набор со стандартным блоком сортировки
блокСортировки: блок набор с заданным блоком сортировки
Выполните последовательно следующие выражения:
Пример:= #(1 3 2 6 11 2) какОтсортированныйНабор
«Сделайте переменную Пример глобальной»
Пример добавить: 9.
^ Пример «обратите внимание на место 9»
Пример блокСортировки: [ :a :b| a*a*a*a*a >= b факториал ]
«Набор автоматически пересортируется»
Пример добавить: 5
^Пример «обратите внимание на место 5»
Класс «Поток» и его подклассы используются для доступа к файлам, устройствам и внутренним объектам, рассматриваемым как последовательности символов или других объектов.
Потоки содержат внутренний указатель текущей позиции и имеют методы для извлечения или включения следующего объекта в текущую позицию. Определяются сообщения для изменения позиции потока, так что есть возможность прямого доступа к объектам.
Рис.2. Иерархия классов для потоков
Экземпляр любого подкласса класса «Поток» можно создать, используя сообщение
Поток на: экзИндексированныйНабор
Все методы экземпляра класса «Поток» можно разделить по следующим категориям:
· доступ-чтение
· следующий (следующий элемент получателя)
· следующий: число (заданное число следующих элементов приемника в виде набора того же вида, что и набор приемника)
· следующаяСтрока (строка текста, состоящая из символов приемника до следующего ограничителя строки)
· следующееСлово (строка, содержащая следующее слово)
· взятьСледующий (следующий объект в потоке приемника без продвижения позиции указателя потока)
· вплотьДо: экзОбъект (набор объектов приемника, начиная со следующего доступного объекта до заданного, но не включая его)
· содержимое (выдает набор, на котором организован поток)
· вОбратномПорядке (выдает набор, образованный из набора приемника с содержимым в обратном порядке)
доступ-запись
вСледующих: экзЦелое разместить: экзОбъект (помещает заданный объект в поток приемника заданное целое число раз)
проверка
· вКонце (истина, если приемник установлен в конец)
· этоПустой (истина, если поток приемника не содержит элементов)
позиционирование
· позиция (текущая позиция потока приемника)
· позиция: экзЦелое (задает позицию потока приемника)
· пропустить: экзЦелое (увеличить позицию приемника на заданное целое)
· пропуститьДо: экзОбъект (продвинуть позицию за заданный объект)
· установитьНаКонец (установить позицию потока в конец)
· установитьНаНачало (позиция потока - в начало)
Пример 1. Ввод из заданного массива
«Вычислить несколько факториалов»
|ввод вывод|
ввод := ПотокЧтения на: #( 1 5 10 20 ).
вывод := ПотокЗаписи на: Массив новыйЭкземпляр.
[ввод вКонце] покаЛожь:[вывод поместитьСледующий: ввод следующий факториал].
^вывод содержимое
Пример 2. Интерактивный ввод данных:
| x y z |
x:= Файл полноеИмя: 'test'.
z:=истина.
«создание файла 'test'»
[z] покаИстина:
[ Курсор смещение: (10@10).
y:=Суфлер подсказка:' Введите фамилию имя отчество'
поУмолчанию:''.
y='' еслиИстина:[ z:=ложь. x закрыть ]
еслиЛожь: [ x поместитьВсеПоследующие: y; символВК ]. ].
«добавив слово в файл, необходимо добавить символ ВК»
Первая строка программы создает экземпляр класса «Файловый поток». Данный
поток организован на основе файла 'test'.
Пример 3. Работа с файлами. Программа располагает фамилии, содержащиеся в файле 'test', в алфавитном порядке и создает новый файл 'test1'.
| x y z |
x:= Файл полноеИмя: 'test'.
z:= ОтсортированныйНабор новыйЭкземпляр.
[x вКонце] покаЛожь:
[ z добавить: (x следующаяСтрока) ].
x закрыть.
y:= Файл полноеИмя:' test1'.
z выполнить: [:слово | y поместитьВсеПоследующие:слово; символВК].
y закрыть.
^z.
Задание 1. Выполните с помощью пункта «показать» (меню рамки) все выражения, приведенные в Таблице 1.
Задание 2. Дополните Таблицу 1, выполнив следующие выражения:
#('массив' 'из' 'строк') размер
'текущее время' вВерхнемРегистре
'привет всем' вОбратномПорядке
#(4 'пять' 5 (5 6)) вОбратномПорядке
65 какСимвол
$D код
3.1415 печатноеИмя
#(1 3 5 7) вПозиции: 2
'Привет' вПозиции: 1 разместить: $п
'быстро' скопироватьОт: 2 до: 5
'здравствуй, Ольга' включает: $л
Задание 3. Выполните следующие выражения:
1-2
3 - 4 «Обратите внимание на пробел между '-' и 3»
'привет, Ольга!' размер + 4
'кто ты?' размер + #(1 2 3 4) размер
#(1 12 24 36) включает: 4 факториал
4 факториал между: 2+4 и: 'компьютер' размер *4
'автоматика' вПозиции: 2
Задание 4. Выполните следующие выражения:
3+4
5*7
5//2
7\\3
2/6
-2 абс
10 сОбратнымЗнаком
11 обратнаяДробь
10 отрицательный
Вычислите выражения и обратите внимание на результат:
3 + 4*2
3+ (4*2)
3*4+11
Посчитайте значение выражения
2-3!*5+5!*(3*4+11)/8.
Замечание: унарное сообщения имеют более высокий приоритет, чем бинарные (например, x - y размер = x - ( y размер )
Задание 1. Написать программу, которая записывает в файл 'test2' все простые числа от 1 до N (число N - вводится пользователем), используя решето Эратосфена.
Решетом Эратосфена называют следующий способ. Выписываются подряд все целые числа от 2 до N. Первое простое число - 2. Вычеркиваем его, а также все числа кратные 2. Первым из оставшихся чисел будет число 3. Оно простое. Опять вычеркиваем 3 и все числа кратные ему. Следующее простое число - 5. Процесс повторяется, пока в данном множестве есть хотя бы один элемент.
Задание 2. Задан массив целых чисел. Написать программу, создающую новый массив, в котором идут сначала все положительные элементы, упорядоченные по возрастанию, затем идут все нулевые элементы, затем - все отрицательные элементы, упорядоченные по убыванию.
Например: задан массив #(1 2 -3 0 0 0 -2 3 -4)
Результат - массив #(1 2 3 0 0 0 -4 -3 -2)
Задание 3. Написать программу поиска максимума в заданном массиве (например: массив:= #(1 3 4 5 2 3 5 7) )
Задание 4. Написать программу, которая считает гласные в заданной строке. (например: строка:='Этот замечательный язык Смолток!')
Задание 5. Используя методы класса Поток, написать программу, которая ищет гласные в заданной строке и выводит их на экран (например: строка:='Этот замечательный язык Смолток!').
Задание 6. Написать программу, которая проверяет, является ли слово полидромом (не используя цикл). Слово называется полидромом, если оно одинаково читается как справа налево, так и слева направо (например: слово:='шалаш').
Задание 1. Написать программу вычисления наибольшего общего делителя двух целых чисел, используя алгоритм Евклида:
ì а, при а=в
НОД( а, в) = í НОД(а-в,в), при а>в
î НОД(а,в-а), при в>а
Задание 2. Добавьте к классу Целое метод, вычисляющий N-е число Фибоначчи
(например: 10 Фибоначчи). Выполните следующее выражение:
#(1 2 3 4 5 6 7 10 20) собрать: [ :m| m фибоначчи ]
Задание 3. Дополнить класс Строка (подкласс класса Набор) методом 'полидром'. Результат - истиналожь.
Задание 4. Добавьте новый класс «Комплексное число», определив необходимые методы класса и экземпляров (создание экземпляра, сумма, произведение комплексных величин и т.п.)