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

Содержимое удалено Содержимое добавлено
Нет описания правки
 
мНет описания правки
Строка 1:
<b>Основы</b>
 
В традицыонном программировании, мы начинаем с задачи которую надо решыть. Мы обдумываем как разделить проблему на меньшые части, затем каждую часть на ещё меньшые части. На каждой стадии мы думаем о том как \emph{<i>сделать}</i> текущую часть работы. Прежде чем сделать что-либо надо сделать какую-нибудь одну вещ, затем другую, затем ещё другую. Таким образом, мы разделяем и решаем проблему делая акцэнт на том что надо \emph{<i>сделать}</i>.
 
При объектно-ориентированном подходе, мы снова начинаем с задачи которую надо решыть. Затем мы пытаемся представить из каких объектов состоит система, какова их ответственность, и как они взаимодействуют. Мы так жэ разделяем проблему на части, но акцэнт делается на объектах и их взаимодействии.
Строка 7:
==Объекты==
 
Что такое объект? В реальном мире мы можэм думать об объектах как о \emph{<i>вещах}</i>: яблоко, машына, человек, дом. В мире программ мы используем объекты которые модэлируют реальный мир, и мы такжэ используем объекты которые делают нашу жызнь проще, такие как поля ввода, текстовые строки, совокупности, числа, файлы, окна, процэссы. Главное качество объекта это то что он можэт иметь имя и можэт быть отличён от объектов другого типа. Давайте рассмотрим пример цэнной бумаги которая продаётся на фондовой биржэ.
 
Каковы свойства объекта? Объект обычно содержыт некоторую информацыю, и он обычно имеет некоторое поведение --- он должэн что-то делать. Наш объект цэнная бумага содержыт информацыю: её название, её текущую цэну, количество \potom!!!, \potom!!!. Она такжэ имеет поведение: она должна давать ответ о новой цэне и она должна накапливать общее количество сделок.
 
Программа Фондовая биржа должна содержать много объектов цэнная бумага, по одному на каждую акцыю продаваемую на биржэ. С объектом можно взаимодействовать посылая ему \emph{<i>сообщения}</i>. Например, если надо узнать текущую цэну акцыи, пусть это будет \verb|<tt>XYZ|</tt> акцыя, надо послать сообщение \verb|<tt>цэна|</tt> объекту акцыя \verb|<tt>XYZ|</tt>. В ответ объект акцыя находит в своих данных текущую цэну и возвращает её.
 
Если фондовая биржа передаёт информацыю \potom!!!, она посылает сообщение \verb|<tt>покупка: количество цэна: цэна|</tt> объекту \verb|<tt>XYZ|</tt> (мы будем подробнее говорить о сообщениях в Главе 2, Сообщения). Когда объект акцыя получает сообщение, он должэн обновить свои данные --- в данном случае он должэн обновить текущую цэну, количество порцэнтов последней сделки и общее количество сделок за день. \emph{<i>Объект содержыт собственные данные плюс сообщения которые он понимает}</i>.
 
Наш объект акцыя содержыт данные: название акцыи, обозначение, текущую цэну, объём последней сделки и объём продаж за день; и сообщения: \verb|<tt>имяАкцыи, обозначение, цэна, последняяСделка, объёмСделок|</tt>, и \verb|<tt>покупка:цэна:|</tt> (плюс некоторые другие). Данные хранятся в переменных экзэмпляра. Каждый объект акцыя имеет свою собственную копию \emph{<i>переменных экзэмпляра}</i>, так что каждая акцыя можэт хранить различные значения цэны, обозначения, и т.д.
 
==Инкапсуляцыя==
 
Когда ты посылаеш сообщение \verb|<tt>покупка:| \verb|количествоАкцый| \verb|цэна:| \verb|цэна|</tt> конкретному объекту акцыя, он обновляет переменные экзэмпляра \emph{<i>цэна, последняяСделка}</i> и \emph{обёмСделок}. Не существует \emph{<i>другова}</i> пути для изменения этих переменных. Ни один другой объект не можэт прочитать или изменить данные объекта XYZ. Это можно сделать только посылая объекту \verb|<tt>XYZ|</tt> сообщение. Некоторые сообщения обновляют данные объекта акцыя, и некоторые сообщения возвращают значения. Но ни один объект не можэт получить доступ к данным напрямую. Данные \emph{<i>инкапсулированы}</i> в объекте. Рисунок~\ref{incapsulxcyx} показывает представление данной инкапсуляцыи.
 
\begin{figure}[!htb]
Строка 29:
\end{figure}
 
Тот факт что данные инкапсулированы означает что мы можэм изменить способ изих хранения. Так долго как мы сохраняем общедоступный интэрфейс который мы определили - сообщения на которые объект отвечает, мы можэм делать всё что захотим внутри объекта. В один день мы можэм решыть хранить цэну в долларах и цэнтах, в следующий день в цэнтах, в следующий день в восьмёрках долларов, и т.д. Так долго как мы такжэ меняем способ которым метод \verb|<tt>цэна|</tt> манипулирует данными до их возвращения, мы поддержываем общедоступный интэрфейс несмотря на то что объект внутренне изменяется.
 
==Классы==
Строка 35:
===Класс как хранилище кода===
 
Допустим что наша программа использует две \emph{<i>УпорядочненныеСовокупности}</i> (совокупность которая хранит элементы в порядке их добавления). Одна хранит телефонные сообщения которые мы получили но на которые не ответили, и другая хранит действия которые мы должны сделать --- элементы действия. Между тем, нам нужны сообщения для добавления элемента в нашу совокупность, и извлечения первого элемента из совокупности.
 
Мы не должны писать методы \verb|<tt>добавить:|</tt> и \verb|<tt>первый|</tt> дважды, один раз для каждого объекта. Вместо этого мы нуждаемся в механизме для написания кода однажды и использования его для обеих УпорядоченныхСовокупностей. Вот откуда появляется концэпцыя \emph{<i>класса}</i>. Класс это просто проэкт или шаблон для того как объект должэн выглядеть: какие переменные он содержыт и какие сообщения он понимает. Мы определили класс УпорядоченнойСовокупности в котором мы написали код для сообщений \verb|<tt>добавить:|</tt> и для \verb|<tt>первый|</tt>. Таким образом вы можэте рассматривать класс УпорядоченнаяСовокупность как хранилище для кода который выполняется когда вы посылаете сообщение. Написав код однажды все УпорядоченныеСовокупности (в нашэм случае две) могут выполнять его.
 
\begin{figure}[!htb]
Строка 47:
\end{figure}
 
Код хранится в \emph{<i>методах}</i>. Когда объект получает сообщение он выполняет \emph{<i>метод}</i> с тем жэ именем. Таким образом мы написали методы и они хранятся в классе. Рисунок~\ref{hraniliwe} показывает пример класса Служащий, показано как класс работает в качестве шаблона и в качестве хранилища кода.
 
===Класс как фабрика===
 
Следующий возникающий вопрос как наша УпорядоченнаяСовокупность создаётся. Как-никак она не появляется с помощью магии. Ответ состоит в том что мы просим \emph{<i>класс}</i> УпорядоченнаяСовокупность создать два \emph{<i>экзэмпляра}</i> УпорядоченнойСовокупности. Следующий код показывает как создаются, и присваиваются переменным, два экзэмпляра УпорядоченнойСовокупности (:= это оператор присвоения).
 
\begin{verbatim}
Строка 60:
Таким образом наряду с тем что класс хранилище для кода он ещё является фабрикой создающей экзэмпляры себя. Точно так жэ как автомобильный завод производит машыны фабрика (класс) УпорядоченнаяСовокупность производит УпорядоченныеСовокупности. Фабрика содержыт проэкт для создания объектов, и шаблон на который похож объект - для данных содержащихся в нём.
 
Сейчас давайте на момент вернёмся назад на один шаг и посмотрим на код вышэ по тексту который создаёт экзэмпляры УпорядоченнойСовокупности. Обратите внимание что мы посылаем сообщение \verb|<tt>новый|</tt> УпорядоченнойСовокупности. Вспомните что мы просим объекты выполнять некоторые вещи посылая им сообщения. Данный код выглядит так как будто класс УпорядоченнаяСовокупность является объектом, и это действительно так. Не только наш собственный экзэмпляр класса УпорядоченнаяСовокупность является объектом, но и фабрика которая создаёт его. Мы называем \emph{<i>классом}</i> объект являющийся фабрикой, и экзэмпляром каждый объект который создаёт фабрика. Так в нашэм случае мы имеем класс УпорядоченнаяСовокупность который создаёт два экзэмпляра УпорядоченнойСовокупности.
 
Из за того что класс содержыт шаблон для индивидуального экзэмпляра УпорядоченнойСовокупности, каждая УпорядоченнаяСовокупность содержыт свои собственные копии переменных экзэмпляра первыйИндэкс и последнийИндэкс. И из за того что класс это хранилище кода, каждый экзэмпляр УпорядоченнойСовокупности использует код класса.
 
===Класс как абстракцыя===
 
Класс является абстракцыей общего поведения и общих данных объекта который он создаёт. Он предоставляет место где общее поведение и общие переменные экзэмпляра могут быть определены. Переменная экзэмпляра это просто слот; он не содержыт данных пока класс не создаст экзэмпляр. \emph{<i>Класс это фабрика с проэктомпраэктом для создания экзэмпляров}</i>. \emph{<i>Он такжэ хранилище кода}</i>.
 
==Наследование==
 
Сейчас давайте рассмотрим другой тип совокупности --- \emph{<i>СортировануюСовокупность}</i>. Наш список действий лучшэ представляется классом СортированаяСовокупность потому что мы предпочитаем чтобы все элементы с высоким приоритетом показывались перед элементами с низким.
 
Большая разница между СортированойСовокупностью и УпорядоченнойСовокупностью это то что при создании элементов они сортируются на основе правила которое мы можэм определить. Однако, большая часть поведения подобна и поэтому большынство кода должно быть одинаковым. Досадно дублировать весь код УпорядоченнойСовокупности для СортированойСовокупности. Не только потому что надо сделать много работы, но и потому что надо такжэ обновлять код СортированойСовокупности если вы сделаете изменения в УпорядоченнойСовокупности.
Строка 76:
Мы хотели бы чтобы СортированаяСовокупность использовала код который ужэ написан для УпорядоченнойСовокупности, так что если код изменится, СортированаяСовокупность тожэ изменилась. Мы хотели бы иметь общий код когда это имеет смысл, например код для нахождения первого и последнего элемента совокупности. Мы такжэ хотели бы иметь различный код для случаев в разным поведением, например нахождение элемента в совокупности. Мы хотели бы чтобы СортированаяСовокупность наследовала поведение УпорядоченнойСовокупности в тех случаях когда они подобны.
 
К счастью мы можэм делать это используя наследование между классами. В объектно ориентированном мире, мы можэм сказать что один класс является \emph{<i>подклассом}</i> другого класса. Так в нашэм примере, СортированаяСовокупность это подкласс УпорядоченнойСовокупности. Это позволяет СортированойСовокупности наследовать весь код и переменные экзэмпляра УпорядоченнойСовокупности. Например, если вы хотите перебрать все элементы в СортированойСовокупности, вы посылаете сообщение \verb|<tt>делать:|</tt>, которое определено в УпорядоченнойСовокупности. СортированаяСовокупность наследует код и её экзэмпляры могут делать то жэ самое что могут делать экзэмпляры УпорядоченнойСовокупности.
 
Если вы не писали код для СортированойСовокупности, она должна наследовать всё что написано для УпорядоченнойСовокупности. Фактически, если вы не изменили некоторое поведение, совсем не имеет смысла создавать новый класс. К счастью, СортированаяСовокупность имеет некоторые отличия в поведении. Есть два типа различий в поведении. Первое, некоторые сообщения должны делать различные вещи. Например, отправка сообщения \verb|<tt>добавить:|</tt> должна добавить объект в конец УпорядоченнойСовокупности, но в случае СортированойСовокупности объект надо добавить в позицыю основанную на правиле сортировки для совокупности. Если мы сделаем:
 
\begin{verbatim}
Строка 96:
\end{verbatim}
 
и рассмотрим совокупность, строки будут в следующем порядке 'abc', 'def', 'xyz', в правильной отсортированной последовательности для строк. Таким образом, в СортированойСовокупности мы не должны наследовать код суперкласса для \verb|<tt>добавить:|</tt>. Вместо этого мы пишэм свой собственный код для метода \verb|<tt>добавить:|</tt> и подменяем код определённый в УпорядоченнойСовокупности.
 
Второй случай когда мы нуждаемся в различном поведении это добавление поведения - делать что-либо что суперкласс не можэт делать. Например, мы должны определить алгоритм сортировки который должэн использоваться экзэмплярами СортированойСовокупности. Мы добавляем поведение очень легко, просто написав новый метод для СортированойСовокупности. Например в случае сортирующего алгоритма мы пишэм метод \verb|<tt>сортирующийБлок:|</tt> который запоминает новый алгоритм для будущего добавления и такжэ для пересортировки совокупности в соответствии с новым алгоритмом. Рисунок~\ref{nasledovanie} показывает пример наследования, переписывания, и добавления методов.
 
\begin{figure}[!htb]
Строка 110:
==Полиморфизм==
 
Помните что сообщения \verb|<tt>добавить:|</tt> различны для УпорядоченнойСовокупности и для СортированойСовокупности? Есть другие типы совокупностей таких как Множэство, Мешок, СвязаныйСписок каждая из которых определяет свою собственную версию \verb|<tt>добавить:|</tt>.
 
Это означает что вы можэте использовать совокупность и не заботиться о том какого она типа; вы просто посылаете сообщение \verb|<tt>добавить:|</tt> и она добавляет объект в себя правильным образом. Другим примером можэт быть окно которое показывает графические объекты. Вместо того чтобы знать о том как изображать окружность и квадрат, окно должно просто послать сообщение графическому объекту ( например: \verb|<tt>графическийОбъект| \verb|изобразиСебяНа: мне|сам</tt>). графическийОбъект можэт быть квадратом или ок\-ружностьюокружностью, но для окна это не важно. Оно просто посылает одинаковые сообщения независимо от типа объекта, и полагает что графическийОбъект знает как изобразить себя. На процэдурном языке вы можэте написать приблизительно так:
 
\begin{verbatim}
Строка 127:
\end{verbatim}
 
Рассмотрим другой пример, мы имеем объект Офис который видит объекты Работник приходящих на работу. Один подход для объекта Офис спросить объект работник какого типа он работник. Если это объект Программист, объект Офис должэн сказать ему начать программировать (\verb|програм|\-\verb|мист|<tt>программист \verb|начниПрограммировать|</tt>). Если это служащий, объект Офис должэн сказать ему отвечай на телефонные звонки (\verb|<tt>служащий| \verb|отвечайНаТелЗвонки|</tt>). Если это мэнеджэр, объект Офис должэн сказать ему работай с бумагами (\verb|<tt>мэнеджэр| \verb|работайСБумагами|</tt>).
 
Такой подход неудобен из за того что надо иметь код единственная задача которого проверять какого типа объект Работник просто спрашывая его, и надо изменять данный код когда добавляется новый тип работника. Лучшый подход для объекта Офис не интересоваться типом работника, а просто говорить ему делать работу(\verb|<tt>работник| \verb|принимайсяЗаРаботу|</tt>). Если объект Программист получает это сообщение, он должэн начать программировать; если объект Служащий получает это сообщение, он должэн начать отвечать на телефонные звонки; если объект Мэнеджэр получает это сообщение, он должэн начать работать с бумагами. Сейчас когда вы добавите новый тип работника, вы просто должны быть уверены что он отвечает на сообщение \verb|<tt>принимайсяЗаРаботу|</tt> и делает соответствующую работу. Мы передали ответственность тем к кому она относится. Рисунок~\ref{polimorfizm} показывает пример полиморфизма.
 
\begin{figure}[!htb]
Строка 139:
\end{figure}
 
Возможность понимания одинаковых сообщений различными способами различными объектами означает что мы можэм \emph{<i>принимать решэния}</i> и \emph{<i>командовать}</i>. Это фундаментальное различие между процэдурным мышлением и объектно-ориентированным мышлением. Интэрпретацыя одного и того жэ сообщения по разному называется \emph{<i>полиморфизм}</i>. Это работает потому что есть разница между \emph{<i>сообщением}</i> и \emph{<i>функцыей}</i>. Когда сообщение посылается объекту, объект просматривает имя сообщения (\emph{<i>селектор}</i> в терминологии Smalltalk) в списке сообщений на которые он отвечает. С селектором сообщения связан метод --- несколько строк кода которые должны быть выполнены. Таким образом, один селектор сообщения можэт быть связан с различным кодом для различных классов.
 
Для меня, определяющим свойством объектно-ориентированного программирования является возможность просто сказать объекту делать что-то, вместо таво чтобы по полученной информацыи делать различные вещи на основании этой информацыи. Полиморфизм это ключевая часть этой возможности. Мы более явно рассмотрим эту технику в Главе 28, Устранение процэдурного кода.
Строка 145:
==Абстрактные суперклассы==
 
Сейчас давайте расшырим идею наследования. СортированаяСовокупность это подкласс \emph{<i>УпорядоченнойСовокупности}</i>. Другие подклассы УпорядоченнойСовокупности включают \emph{<i>РегулярнуюСовокупность}</i> и \emph{<i>СвязынныйСписок}</i>. УпорядоченныеСовокупности, Массивы и СвязанныеСписки имеют не\-котороенекоторое общее поведение которое определено в классе РегулярнаяСовокупность. Однако, вы не можэте создать экзэмпляр РегулярнойСовокупности (вы можэте, но вы получите ошыбку если попытаетесь что-либо сделать с ней).
 
Класс УпорядоченнаяСовокупность существует как место для хранения кода который является общим для упомянутых классов. Общее поведение отделяется помещается в абстрактный суперкласс, который не можэт иметь экзэмпляров --- т.е. не должэн создавать экзэмпляры себя. Например методы \verb|<tt>копироватьОт:до:|</tt> и \verb|<tt>наличие---|</tt>: оба написаны в РегулярнойСовокупности и наследуются её подклассами.
 
Таким образом, абстрактный суперкласс это класс который не имеет своих экзэмпляров, но который существует как хранилище для общего кода. Абстрактный суперкласс РегулярнаяСовокупность сам имеет абстрактный суперкласс, \emph{<i>Совокупность}</i>. Совокупность это такжэ суперкласс для \emph{<i>Множэства}</i> и \emph{<i>Мешка}</i>, совокупностей для которых нет понятия порядка. Совокупность обеспечивает поведение которое является общим для всех совокупностей, такое как \verb|<tt>пустая?|</tt>, \verb|<tt>собрать:|</tt>, \verb|<tt>делать:|</tt> и \verb|<tt>включает:|</tt>. (Некоторые подклассы переопределяют эти методы для осуществления подходящего поведения. Однако, многие подклассы наследуют поведение напрямую.) Рисунок~\ref{ierarhix} показывает малую часть иерархии Совокупностей.
 
\begin{figure}[!htb]
Строка 161:
==Резюмэ==
 
\item* Объекты инкапсулируют данные и поведение (код).
\begin{itemize}
\item* Класс это фабрика которая содержыт план для создания экзэмпляров. Он является хранилищем для кода который выполняется его экзэмплярами.
\item Объекты инкапсулируют данные и поведение (код).
\item* Классы располагаются в иерархии наследования которая позволяет объектам наследовать поведение (и код) от других классов находящихся выше по иерархии.
\item Класс это фабрика которая содержыт план для создания экзэмпляров. Он является хранилищем для кода который выполняется его экзэмплярами.
\item* Работа выполняется путём посылания сообщений другим объектам, говорящих им сделать что-либо или возвратить что-либо.
\item Классы располагаются в иерархии наследования которая позволяет объектам наследовать поведение (и код) от других классов находящихся выше по иерархии.
\item* Многие различные объекты понимают одинаковые сообщения но делают различные вещи когда они получают их. То есть, они выполняют различные методы (полиморфизм).
\item Работа выполняется путём посылания сообщений другим объектам, говорящих им сделать что-либо или возвратить что-либо.
\item Многие различные объекты понимают одинаковые сообщения но делают различные вещи когда они получают их. То есть, они выполняют различные методы (полиморфизм).
\end{itemize}