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

Содержимое удалено Содержимое добавлено
Новая: <b>Методы</b> Методы содержат код который выполняется в ответ на присланное сообщение. В отличии от C ил...
(нет различий)

Версия от 06:43, 5 апреля 2007

Методы

Методы содержат код который выполняется в ответ на присланное сообщение. В отличии от C или C++ в которых могут быть функции не возвращающие значения, в Смолтоке все методы возвращают значение. Если нет явного возвращения переменной, метод должен возвратить сам, объект вызвавший метод.


Типы методов

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


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

Длинна метода

В библиотеке классов VisualWorks, средняя длинна метода считается равной 7 строкам. Короткий метод хорош потому что для программиста легко понимать что он делает. Короткий метод также легко использовать заново и легко для подкласса переопределять его для изменения поведения. Поэтому хорошая идея определить ``стандартный размер браузера и руководствоваться тем что все методы должны помещаться в окно браузера. Если метод больше, обычно возможно разбить его на меньшие методы разделяя концепции которые ты делаеш и помещая каждую в свой метод. Например, длинный метод может разделяться на короткие методы как здесь:

МойКласс>>мойМетод
  сам делайПервуюВещ.
  (некотороеВыражэние)
    истина: [сам делайВторуюВещ]
    лож: [сам делайТретьюВещ.
          сам делайЧетвёртуюВещ.
    ]

Названия методов

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

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

Глупые методы

Если метод короткий, хорошо назван и у него осмысленные имена переменных, он должен быть довольно понятным. Если комментарий класса хорошо описывает общее поведение объекта и переменные экземпляра, тогда хороший метод не нуждается в дополнительном комментарии. Мне очень нравится идея о \emph{глупых методах}. (Я бы хотел бы выразить признательность создателю этого метода но к сожалению я не могу вспомнить где я прочитал об этой идеи.)

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

Форматирование метода

Форматировщик делает хорошую работу по форматированию методов для вас. Я придерживаюсь правила игнорировать форматирование когда я пишу новый метод, затем запустить форматировщик. Мне не нравится как работает форматировщик, я переформатирую код вручную. Есть несколько примером как я могу переформатировать текст когда мне не нравится результат форматирования. Для сохранения места я не показываю оригинальное форматирование; чтобы его увидеть вы можете набрать его и запустить форматировщик.

мойМетод: аПараметр
  аПараметр
     делайЭто;
     делайТо;
     делайЧтоНибудьЕщё
мойМетод: аПараметр
  сам ---
---

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

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

a<b | c<d
(a<b) | (c<d)
a<b | (c<d)

Открытые и закрытые методы

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

В Smalltalk нет такой концэпцыи. Все методы доступны для всех объектов --- они только должны посылать правильные сообщения. Однако, понятие открытых и закрытых методов полезно; вы на самом деле не хотите чтобы другие объекты посылали сообщения которые существуют только как вспомогательные. Допустим вы решыли изменить способ выполнения чего-нибудь. Вы не должны предохранять всё с помощью закрытого интэрфейса. Вы должны суметь скрыть поведение так чтобы другие объекты могли использовать открытый интэрфейс и вы могли свободно менять деталии реализацыи.

Из за таво что в Smalltalk'е нет закрытых методов, любые различия между закрытыми и открытыми методами производятся с помощью использования соглашэний. Одним из таких соглашэний является использование слова \verb|закрытые| в имени протокола для закрытых методов. Ты можэте увидеть имя протокола \verb|закрытые| или \verb|доступ-закрыт|. Неудобство этой схемы в том что ты не всегда обращаш внимание на имя протокола. Если ты просматриваеш методы используя отправителей, implementors и сообщения, ты не различатеш протокол поэтому легко можно использовать особый протокл.

Техника которая мне нравится описана Bob Brodd в The Smallatlk Report, Nov-Dec, 1994. Все закрытые методы имеют приставка мой. Теперь nы используеi смысл Русского языка для предотвращения использования закрытых методов. Обычно что-нибудь вроде \verb|аОбъект| \verb|мойДелайЧтоНибудь| выглядит странно, принимая во внимание что выглядит разумным сказать \verb|сам| \verb|мойДелайЧтоНибудь|. Если ты где-нибудь видиш сообщение \verb|мой| посылаемое чему-нибудь отличному от \verb|сам|, опасайся --- ты возможно видиш использование закрытого метода как будто он открытый. Здесь приведён пример использования приставка \verb|мой| для закрытого метода.

СоздательОбраза>>создатьОбраз
  я мой---

Если ты используеш технику \verb|мой|, есть два основных подхода которых nы можэш придержываться. Один делать всё открытым пока ты знаеш что эти методы не должны вызываться отдельно. Другой сначала сделать все методы закрытыми, затем делать их открытыми когда ты найдёш сообщение которое должно посылаться другим объектом.

\potom

\potom

\potom

Возвращаемое методом значение

В Smalltalk'е, все методы возвращают значение. Нет такова понятия как void функцыя в C++. По умолчанию все методы возарыщают объект которому было послано сообщение. Таким образом, если нет явного возвращаемого значения, в действительности последняя строка метода выглядит подобно этой:

^сам

\verb|^| это символ возвращаемого значения и \emph{сам} ссылается на получателя сообщения --- побъект выполняющий метод. Большынство методов неявно возвращают \emph{сам}. В VisualWorks Browser, если вы нажмёте кнопку \emph{шыфт} пока метод выделен мышю вы можэте увидеть дэкомпилированный код, который действительно заканчивается \verb|^сам|. Возвращение (\verb|^|) выполняется после того как все другие посланные сообщения и присваивания выполнятся.

Возвращение объекта в соответствии с именем метода

Часто имя метода сообщает тебе тип значения которое будет возвращено. Например, имя метода которое заканчивается \verb|?| обычно возвращает \emph{Булево} значение, \emph{истина} или \emph{лож}. Например, \verb|пустой?|, \verb|ноль?|. Сообщения начинающиеся с \verb|как| обычно возвращают указанную вещ. Например сообщение \verb|какСортированнаяСовокупность| посланное совокупности должно возвратить СортированнуюСовокупность. Сообщение \verb|какЧисло| посланное строке должно возвратить число соответствующего типа. (Однако, сообщение \verb|какСтрока| не опредено для чисел поэтому ты должэн использовать вместо нево сообщение \verb|строкаДляПечати| или \verb|показатьСтроку|.)

Методы которые добавляют объект в совокупность, такие как \verb|добавить:| и \verb|от:поместить:|, возвращают объект который добавлен. Методы которые удаляют один объект из совокупности, такие как \verb|удалить:| и \verb|удалитьПервый|, возвращают объект который был удалён. Из за этого стоит знать о сообщении \verb|тысам|. Следующий пример показывает как использовать сообщение \verb|тысам| \potom.

совокупность := Список новый
  добавить: этотОбъект;
  добавить: тотОбъект;
  тысам.

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

Возвращение объекта определённого последним выражэнием

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

Защитное условие

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

МойКласс>>некоторыйМетод
  (некоторое условие) истина: [
     сам делатьОдно.
     сам делатьДругое.
     сам выполнятьДригиеСтроки.
  ]

Однако, часто лучше возвратить \verb|сам| из блока \verb|лож:|, затем выполнить основной код. Таким образом мы получаем защитное условие охраняющие вход в метод.

МойКласс>>некоторыйМетод
  (некоторое условие) лож: [^сам].
  сам делатьОдно.
  сам делатьДругое.
  сам выполнятьДригиеСтроки.

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

Постоянство возвращаемого объекта

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

Потеряные методы

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

МойКласс>>удалитьПробелыИз: аСтрока
  ... удаление начальных и конечных пробелов ...
  ^ новаяСтрокаБезПробелов

Однако, это очень процедурный способ написания кода. Если ты думаеш в терминах объектов, ты расчитываеш как распределяется ответственность, и просиш объекты делать вещи. Пока \emph{МойКласс} действительно не отвечает за удаление пробелов из строки, чьей должна быть эта ответственность? Наиболее очевидное место для этого класс \emph{Строка} (или один из её суперклассов). Затем ты можеш сказать строке убрать пробелы из себя.

урезаннаяСтрока := строка убратьПробелы.

Количество методов

Правила о том сколько методов должно быть в объекте нет, но если ты находиш что у объекта много больше методов чем у других, возможно ты неудачно распределил объём работ. В хорошей объектно-ориентированной системе, у тебя нет очень умных объектов. Взамен ты имееш равнозначные взаимодействующие объекты. За более подробной информацией обращайся к Главе \potom, Объектно-ориентированное мышление.

Параметры по умолчанию

В C++, ты можеш не задавать некоторые параметры при вызове функции и они будут иметь значение по умолчанию (предполагается что функция использует параметры по умолчанию). В Смолтоке нет такова свойства. Взамен, ты часто можеш видеть методы которые ничего больше не делают кроме вызова других методов с дополнительными параметрами.

Хороший пример такого метода это \verb|changed|. Когда ты вызываеш механизм зависимости, ты используеш \verb|changed| чтобы определить что что-то изменилось. Ты используеш \verb|changed:| чтобы определить что изменилось, и \verb|changed:with:| чтобы определить новое значение.

\potom

Шаблон метода

Шаблон метода (который ты видиш когда просматриваеш методы но не выделил ни одного метода) определён в \verb|Behavior>>sourceCodeTemplate|. Если он тебе не нравится, ты можэш изменить ево. Одним из примеров как это сделать рассмотрен в Главе \potom, Настнойка окружэния.