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

Содержимое удалено Содержимое добавлено
Новая: <b>Методы</b> Методы содержат код который выполняется в ответ на присланное сообщение. В отличии от C ил...
 
Нет описания правки
Строка 1:
<b>Методы</b>
 
Методы содержат код который выполняется в ответ на присланное сообщение. В отличии от C или C++ в которых могут быть функции не возвращающие значения, в Смолтоке все методы возвращают значение. Если нет явного возвращения переменной, метод должен возвратить <tt>сам</tt>, объект вызвавший метод.
 
Строка 16 ⟶ 14 :
 
As a general philosophy, лучше всего пытаться и делать так чтобы ваши методы принадлежали только к одному типу. Пытайтесь избегать методов которые одновременно что-либо делают и возвращают значения. Иногда это невозможно, но в гораздо меньшем числе случаев чем вы ожидаете. В отличии от языков, в которых проверяется тип возвращаемого значения, Смолток предоставляет механизм исключений который позволяет обходить эту проверку.
 
<!--
As a general philosophy, it's better to try and make your methods one type or the other. Try to avoid methods that both do something and return a meaningful object. Sometimes it will be unavoidable, but less often than you might expect. Unlike languages where you have to check the status returned from a function call, Smalltalk provides an exception handling mechanism that allows you to bypass the whole status checking aspect of error handling.
-->
 
==Длинна метода==
 
В библиотеке классов VisualWorks, средняя длинна метода считается равнойравна 7 строкам. Короткий метод хорош потому что для программиста легко понимать что он делает. Короткий метод также легко использовать заново и легко для подкласса переопределять его для изменения поведения. Поэтому хорошая идея определить ``стандартный'' размер браузера и руководствоваться тем что все методы должны помещаться в окно браузера. Если метод больше, обычно возможно разбить его на меньшие методы разделяя концепции которые ты делаеш и помещая каждую в свой метод. Например, длинный метод может разделяться на короткие методы как здесь:
 
<!--
In the VisualWorks class library, the average Smalltalk method length is reputed to be seven lines. A short method is a good method because it makes it easy for programmers to understand what the method is doing. A short method is also easier to reuse and easier for subclasses to override in order to modify the behavior. For these reasons it is a good idea to define a "standard" sized browser and have a guideline that all methods should fit in the browser window. If a method is larger, it's usually possible to break it into smaller methods by abstracting out the concepts of what you are doing and putting each concept in its own method. For example, a long method may end up as a short method such as:
-->
 
МойКласс>>мойМетод
Строка 32 ⟶ 38 :
 
Из за того что методы которые помещаются на экране более легки для понимания, не имеет смысла уменьшать понятность при помощи неясных имён. Используйте имена для методов которые по возможности ясны. Не используйте аббревиатур если они не стандартны для всех кто работает в проекте. Так как вы не пишите имена в Смолток очень часто, не повредит иметь длинные имена которые подробны и понятны.
 
<!--
Because short methods that fit in a screen can be more easily understood, it doesn't make sense to prevent that understanding with poor names. Use method and variable names that are as explicit as possible. Don't abbreviate words unless they are standard abbreviations understood by everyone working on the project. Since you don't type names very often in Smalltalk, it doesn't hurt to make them long enough to be very explicit and understandable.
-->
 
Имена методов должны говорить о том что метод делает. Не экономьте буквы; более важна ясность имени чем его длинна. Программист должен быть способен посмотрев на код немедленно сказать что он делает, просто прочитав имя. Однако, не всегда просто подобрать хорошее имя когда ты просто смотрите на метод. Когда метод будет вызываться, когда ты будете посылать сообщение, тогда ты вероятно найдёш хорошее имя. Поэтому, когда ты пишиш метод ево имя может быть хорошим, но будь готов изменить его когда ты начнёш использовать его в других методах.
 
<!--
Method names should say exactly what the method does. Don't be stingy with the number of characters; it's more important to be understandable than short. A programmer should be able to pick up someone else's code and immediately know what the method does, just be reading the name. However, it's not always easy to come up with a great method name when you are looking at the method itself. It's when the method is being invoked, when you are doing the message send, that you'll get the best idea of how good the name is. If it makes sense in the context where it is sent, then you've probably got a good name. So, while it's okay to name the method when you are writing it, be prepared to go back and change the name after you use it in other methods.
-->
 
==Глупые методы==
 
Если метод короткий, хорошо назван и у него осмысленные имена переменных, он должен быть довольно понятным. Если комментарий класса хорошо описывает общее поведение объекта и переменные экземпляра, тогда хороший метод не нуждается в дополнительном комментарии. Мне очень нравится идея о \emph{глупых методах}. (Я бы хотел бы выразить признательность создателю этого метода но к сожалению я не могу вспомнить где я прочитал об этой идеи.)
 
<!--
If a method is short, has a good name, and has well thought out names for its variables, it will be fairly understandable. If class comments describe the general behavior of the object and describe the instance variables well, a good method doesn't need much comment. I really like the idea of stupid methods. (I'd like to give credit to the creator of the term but unfortunately I can't remember where I read about the idea.)
-->
 
То что метод глупый означает что для него не надо никакой документации. Проблема с документацией заключается в том что она делает метод длиньше, и если у вас есть достаточно длинный метод который нуждается в серьёзной документации, вы усложняете проблему тем что делаете метод длиннее и он может не поместиться на экране. Если метод не помещается на экран, он хуже быстро понимается программистом. Наибольшая похвала для метода это то что он ``реально глупый''.
 
<!--
A stupid method is one that is so obvious that it doesn't need any documentation. The problem with
documentation is that it makes a method longer, so if you have a method that is long enough to need some serious documentation, you compound the problem by making it longer and less able to fit on a screen. Not fitting on a screen, it is less readily grasped by a programmer. The ultimate compliment of a method is "that method is really stupid."
-->
 
==Форматирование метода==
 
Форматировщик делает хорошую работу по форматированию методов для вас. Я придерживаюсь правила игнорировать форматирование когда я пишу новый метод, затем запустить форматировщик. Мне не нравится как работает форматировщик, я переформатирую код вручную. Есть несколько примером как я могу переформатировать текст когда мне не нравится результат форматирования. Для сохранения места я не показываю оригинальное форматирование; чтобы его увидеть вы можете набрать его и запустить форматировщик.
 
<!--
The formatter does a pretty good job of formatting methods for you. My rule is to ignore formatting when I'm creating a new method, then to run the formatter. If I don't like what the formatter does, I'll reformat the code by hand. Here are a few examples of how I might reformat when I don't like the formatter results. To save space I won't show the original formatting; to see it, you'll have to type in the code and run the formatter.
-->
 
мойМетод: аПараметр
Строка 57 ⟶ 84 :
 
Некоторые находят формат форматировщика сложным для чтения, особенно в случае сложного, волжэнного кода. Некоторые ставят закрывающуюся квадратную скобку на отдельной строке. Компромисс \potom. Один из ответов почему код солжэн для чтения: метод вероятней всего очень длинный, слишком сложный, или оба случая. Поэтому вы можэте запускать форматировщик для измененения вашэго кода так чтобы он был более элегантным и понятным.
 
<!--
Some people find the formatter's format too difficult to read, especially in the case of complex, nested code. An approach preferred by some is to put each closing square bracket on its own line. The trade-off is that it becomes less likely that a method will fit into one screen, which is a strong goal of mine. One answer is that if the code is difficult to read, the method is very likely too long, too complex, or both. So you might call the formatter a benefit if it forces you to refactor your code to make it more elegant and comprehensible.
-->
 
Чтобы улучшыть понятность часто стоит добавить излишние скобки. Программист смотрящий на код и применяющий правила первенства можэт всегда определить порядок вызова методов, но вы можэте укоротить этот процэсс если сгруппируете некоторые вещи с помощью скобок. Так как форматировщик убирает излишние скобки но оставляет нужные, вы такжэ можэте использовать его для определения мест где скобки нужны. Например, первое выражэние нижэ вызывает исключение, второе делает то что вы хотите, и третье выражэние получается из второго после обработки форматировщиком. Если у тебя более сложный пример, возможно стоит оставить удалённые скобки.
 
<!--
To improve clarity it's often worth putting in redundant parentheses. A programmer looking at code and
working through the message precedence rules can always figure out what is happening, but you can shorten the process if you add parentheses to group things. Since the formatter removes redundant parentheses but leaves required parentheses, you can also use it to tell you where parentheses should be. For example, the first conditional below causes an exception, the second conditional shows what you intend, and the third conditional is what the formatter gives you when you format the second conditional. If you had something more complex, it might be worth leaving the extra parentheses in.
-->
 
a<b | c<d
Строка 67 ⟶ 103 :
 
В C++ есть понятие открытых и закрытых функцый. Открытые функцыи это те которые можэт вызывать каждый объект. Закрытые функцыи это те которые можэт вызывать только экзэмпляр класса который их определил, или его подкласс (на самом деле защищённые функцыи в последнем случае).
 
<!--
In C++ there is the notion of public and private ructions. Public functions are ones that any object can invoke. Private functions are ones that are accessible only to instances of the class that defines them, or its subclasses (actually protected functions in the latter case).
-->
 
В Smalltalk нет такой концэпцыи. Все методы доступны для всех объектов --- они только должны посылать правильные сообщения. Однако, понятие открытых и закрытых методов полезно; вы на самом деле не хотите чтобы другие объекты посылали сообщения которые существуют только как вспомогательные. Допустим вы решыли изменить способ выполнения чего-нибудь. Вы не должны предохранять всё с помощью закрытого интэрфейса. Вы должны суметь скрыть поведение так чтобы другие объекты могли использовать открытый интэрфейс и вы могли свободно менять деталии реализацыи.
 
<!--
Smalltalk does not have such a concept. All methods are accessible to all objects — they only have to send the correct message. However, the notion of public and private methods is useful; you really don't want other objects sending messages that exist only to help with the implementation details. Suppose you decide to change the way something is implemented. You don't want to have to preserve all the private interfaces. You want to be able to encapsulate behavior so that other objects can use the public interface and you can be free to change the implementation details.
-->
 
Из за таво что в Smalltalk'е нет закрытых методов, любые различия между закрытыми и открытыми методами производятся с помощью использования соглашэний. Одним из таких соглашэний является использование слова \verb|закрытые| в имени протокола для закрытых методов. Ты можэте увидеть имя протокола \verb|закрытые| или \verb|доступ-закрыт|. Неудобство этой схемы в том что ты не всегда обращаш внимание на имя протокола. Если ты просматриваеш методы используя отправителей, implementors и сообщения, ты не различатеш протокол поэтому легко можно использовать особый протокл.
 
<!--
Because there are no private methods in Smalltalk, any distinction between private and public methods has to be made using standards. One standard is to use the word private in the protocol names for private methods. You might see aprotocol named private or private-accessing . The disadvantage of this scheme is that you don't always notice the protocol name. If you are browsing methods using senders, implementors, and messages, you are not told the protocol so may easily decide to use a particular message.
-->
 
Техника которая мне нравится описана Bob Brodd в The Smallatlk Report, Nov-Dec, 1994. Все закрытые методы имеют приставка мой. Теперь nы используеi смысл Русского языка для предотвращения использования закрытых методов. Обычно что-нибудь вроде \verb|аОбъект| \verb|мойДелайЧтоНибудь| выглядит странно, принимая во внимание что выглядит разумным сказать \verb|сам| \verb|мойДелайЧтоНибудь|. Если ты где-нибудь видиш сообщение \verb|мой| посылаемое чему-нибудь отличному от \verb|сам|, опасайся --- ты возможно видиш использование закрытого метода как будто он открытый. Здесь приведён пример использования приставка \verb|мой| для закрытого метода.
 
<!--
The technique I like is one described by Bob Brodd in The Smalltalk Report, Nov-Dec, 1994. All private
methods are prefixed with my. Now you use common sense English to prevent the public use of private methods. Basically it looks strange to see something like anObject myDoThis, whereas it looks reasonable to say self myDoThis. If you ever see a my message sent to anything other than self, be suspicious — you are probably seeing a private method being used as if it were public. Here's an example of using the my prefix for private methods.
-->
 
СоздательОбраза>>создатьОбраз
Строка 78 ⟶ 131 :
 
Если ты используеш технику \verb|мой|, есть два основных подхода которых nы можэш придержываться. Один делать всё открытым пока ты знаеш что эти методы не должны вызываться отдельно. Другой сначала сделать все методы закрытыми, затем делать их открытыми когда ты найдёш сообщение которое должно посылаться другим объектом.
 
<!--
If you use the my technique, there are two basic approaches you could take. One is to make everything public unless you know it is a support method that shouldn't be invoked in isolation. The other is to start by making all methods private, then making them public as you come across a message that needs to be sent by another object.
-->
 
\potom
 
<!--
The advantage of the first approach is that you can't predict how other people will want to use your class, and if you make methods private by default, you don't give people the opportunity to be fully creative. The advantage of the second approach is that by making methods private by default, you define a public interface to your object and don't open up the implementation details to other objects. I generally use the latter philosphy because I want my objects tightly encapsulated. However, I also make the distinction between domain specific objects and general reusable objects; the latter usually have more public methods.
-->
 
\potom
 
<!--
We can extend the concept of my methods to include friend methods. A friend message is one that can be
sent between friend objects. Suppose you have a nicely encapsulated subsystem that consists of several
collaborating objects. None of these objects has a life outside the subsystem, and they don't expect to receive messages from objects outside the subsystem. We can consider these objects all friends of each other, and define a prefix such as f r to denote messages that can only be sent by a friend. Each class that defines friend methods would have to provide documentation in the class comments describing exactly which classes are friends. Any programmer wanting to use a message starting with f r would have to look at the class comments to find out if the sending object is actually a friend.
-->
 
\potom
 
<!--
In Chapter 29, Meta-Programming, we will show an extension to Class that automatically creates both public and private accessors for all our instance variables when we define a class.
-->
 
==Возвращаемое методом значение==
 
В Smalltalk'е, все методы возвращают значение. Нет такова понятия как void функцыя в C++. По умолчанию все методы возарыщают объект которому было послано сообщение. Таким образом, если нет явного возвращаемого значения, в действительности последняя строка метода выглядит подобно этой:
 
<!--
In Smalltalk, all methods return a value. There is no such thing as C++'s void function. By default all methods return the object the message was sent to. So, if there is not an explicit return in a method, in effect the last line of the method looks like:
-->
 
^сам
 
\verb|^| это символ возвращаемого значения и \emph{сам} ссылается на получателя сообщения --- побъект выполняющий метод. Большынство методов неявно возвращают \emph{сам}. В VisualWorks Browser, если вы нажмёте кнопку \emph{шыфт} пока метод выделен мышю вы можэте увидеть дэкомпилированный код, который действительно заканчивается \verb|^сам|. Возвращение (\verb|^|) выполняется после того как все другие посланные сообщения и присваивания выполнятся.
 
<!--
^ is the return symbol and self refers to the message receiver — the object executing the method. Most
methods implicitly return self. In the VisualWorks Browser, if you hold the shift key down while selecting a Methods 33 method with the mouse you will see the decompiled code, which actually has a A s e l f at the end. The return (A) is executed after all other message sends and assignments in the statement have been done.
-->
 
===Возвращение объекта в соответствии с именем метода===
 
Часто имя метода сообщает тебе тип значения которое будет возвращено. Например, имя метода которое заканчивается \verb|?| обычно возвращает \emph{Булево} значение, \emph{истина} или \emph{лож}. Например, \verb|пустой?|, \verb|ноль?|. Сообщения начинающиеся с \verb|как| обычно возвращают указанную вещ. Например сообщение \verb|какСортированнаяСовокупность| посланное совокупности должно возвратить СортированнуюСовокупность. Сообщение \verb|какЧисло| посланное строке должно возвратить число соответствующего типа. (Однако, сообщение \verb|какСтрока| не опредено для чисел поэтому ты должэн использовать вместо нево сообщение \verb|строкаДляПечати| или \verb|показатьСтроку|.)
 
<!--
Often the method name will tell you what type of object will be returned. For example, method names that start with is will usually return a Boolean, true or false. For example, isEmpty, isNil. Messages that start with as will usually return the thing specified. For example, asSortedCollection sent to a collection will return a SortedCollection. The asNumber message sent to a string will return a number of the appropriate type. (However, asString is not implemented by numbers so you should use print String or displayString instead.)
-->
 
Методы которые добавляют объект в совокупность, такие как \verb|добавить:| и \verb|от:поместить:|, возвращают объект который добавлен. Методы которые удаляют один объект из совокупности, такие как \verb|удалить:| и \verb|удалитьПервый|, возвращают объект который был удалён. Из за этого стоит знать о сообщении \verb|тысам|. Следующий пример показывает как использовать сообщение \verb|тысам| \potom.
 
<!--
Methods that add objects to collections, such as add: and at:put:, return the object that is added. Methods that remove single objects from collections, such as remove: and remove First , return the object that was removed. Because of this it's worth knowing about the yourself message. The following example illustrates how the use of yourself ensures that collection contains the list rather than the last object added (the example makes use of message cascading, which we will talk about in Chapter 6, Special Variables, Characters, and Symbols).
-->
 
совокупность := Список новый
Строка 105 ⟶ 193 :
 
Последовательность и предсказуемость большое достоинство, поэтому при добавлении метода данного типа в твой собственный класс, следуй общеупотребительным шаблонам. Иначе ты запутаеш всех программистов которые будут читать или использовать твой код.
 
<!--
Consistency and predictability are great virtues, so when adding these types of methods to your own classes, follow the common usage patterns. Otherwise you'll confuse every programmer who looks at or uses your code.
-->
 
===Возвращение объекта определённого последним выражэнием===
 
Если объект возвращает что-либо отличное от сам, последняя строка или последнее выражэние в методе должно определить что возвращать. Предполагается что когда вы видите явное возвращение в концэ метода это означает что получатель должэн позаботиться о том что делать с возвращённым значением. По этой причине, не используй \verb|^|сам в концэ метода пока это явно не подразумевается получателем.
 
<!--
If a method returns something other than self, the last line or the last statement in the method will specify what is being returned. The assumption when you see an explicit return at the end of the method is that the message sender will care about what is being returned. For this reason, don't do A self at the end of the method unless this has an explicit meaning for the sender.
-->
 
===Защитное условие===
 
Если ты хочиш выполнить тело метода при выполнении некоторого условия, очевидный способ сделать это:
 
<!--
If you will execute the method body only if some condition is true, the obvious way to do this is:
-->
 
МойКласс>>некоторыйМетод
Строка 122 ⟶ 222 :
 
Однако, часто лучше возвратить \verb|сам| из блока \verb|лож:|, затем выполнить основной код. Таким образом мы получаем защитное условие охраняющие вход в метод.
 
<!--
However, it is often better to return self from an if False: block, then execute the main code. Thus we have a guard clause protecting entry to the method.
-->
 
МойКласс>>некоторыйМетод
Строка 130 ⟶ 234 :
 
Это делает код немного проще для понимания потому что не разветвлённый код лучше условного. Это подход противоречит структурному подходу одной точки входа, выхода. Это правило было создано для решения проблемы понятности длинных функций с многими точками входа выхода. Однако, методы Смолтока обычно короткие, поэтому просто увидеть что происходит.
 
<!--
This makes the code a little easier to follow because it's all straight line code rather than conditional. This approach goes against the structured programming adage of one entry point, one exit point. The rule was created to solve the understandability problem of long functions with multiple entry and exit points. However, Smalltalk methods are usually short, so it's easy to see exactly what is happening.
-->
 
===Постоянство возвращаемого объекта===
 
Если твой метод неявно возвращает \verb|сам| в конце, используй \verb|^сам| если ты возвращаеш значение раньше. Не возвращай другие значения, такие как \verb|ноль|, исключая случай когда \verb|ноль| имеет особый смысл для получателя.
 
<!--
If your methods implicity returns self at the end, use ^self to return earlier. Don't return a different value, such as nil, unless nil has a specific meaning to the sender.
-->
 
==Потеряные методы==
 
Если метод не ссылается на переменные экземпляра, а просто оперирует с параметрами, ты можеш спросить определён ли метод в правильном месте. Если метод манипулирует параметром, возможно код должен быть определён в классе параметра. Например, при работе со строками, ты можеш решить что тебе надо удалить начальные и конечные пробелы. Поэтому ты пишиш новый метод для твоего класса который удаляет пробелы.
 
<!--
If a method doesn't reference any instance variables, and simply operates on parameters, you might ask if the method is defined in the right place. If the method is manipulating a parameter, perhaps the code should be defined by the class of the parameter. For example, when working with a string, you may decide you need to remove the leading and trailing white space. So you write a new method for your class that trims the white space.
-->
 
МойКласс>>удалитьПробелыИз: аСтрока
Строка 144 ⟶ 260 :
 
Однако, это очень процедурный способ написания кода. Если ты думаеш в терминах объектов, ты расчитываеш как распределяется ответственность, и просиш объекты делать вещи. Пока \emph{МойКласс} действительно не отвечает за удаление пробелов из строки, чьей должна быть эта ответственность? Наиболее очевидное место для этого класс \emph{Строка} (или один из её суперклассов). Затем ты можеш сказать строке убрать пробелы из себя.
 
<!--
However, this is a very procedural way of writing code. If you are thinking in terms of objects, you figure out where the responsibility really lies, and tell objects to do things. Since MyClass really is not responsible for removing white space from strings, where should that responsibility lie? The most obvious place is the class String (or one of its superclasses). You can then tell your string to strip itself of white space.
-->
 
урезаннаяСтрока := строка убратьПробелы.
Строка 150 ⟶ 270 :
 
Правила о том сколько методов должно быть в объекте нет, но если ты находиш что у объекта много больше методов чем у других, возможно ты неудачно распределил объём работ. В хорошей объектно-ориентированной системе, у тебя нет очень умных объектов. Взамен ты имееш равнозначные взаимодействующие объекты. За более подробной информацией обращайся к Главе \potom, Объектно-ориентированное мышление.
 
<!--
There is no rule for how many methods an object should have, but if you find that one object has many more methods than other objects, it may be that you are not distributing the workload well. In a good Object-Oriented system, you don't have super-intelligent objects. Instead, you have many peer-type objects cooperating. For more information, see Chapter 9, Object-Oriented Thinking.
-->
 
==Параметры по умолчанию==
 
В C++, ты можеш не задавать некоторые параметры при вызове функции и они будут иметь значение по умолчанию (предполагается что функция использует параметры по умолчанию). В Смолтоке нет такова свойства. Взамен, ты часто можеш видеть методы которые ничего больше не делают кроме вызова других методов с дополнительными параметрами.
 
<!--
In C++, you can leave out parameters in function calls and the parameters will be defaulted (assuming the function is written this way). In Smalltalk no such capabilitiy exists. Instead, you often see a method do nothing other than invoke another method with an additional parameter.
-->
 
Хороший пример такого метода это \verb|changed|. Когда ты вызываеш механизм зависимости, ты используеш \verb|changed| чтобы определить что что-то изменилось. Ты используеш \verb|changed:| чтобы определить что изменилось, и \verb|changed:with:| чтобы определить новое значение.
 
<!--
A good example of this is the changed message. When you invoke the dependency update mechanism, you
use changed to specify that something has changed. You use changed: to specify what has changed, and
changed: with: to specify the new value.
-->
 
\potom
Строка 162 ⟶ 296 :
 
Шаблон метода (который ты видиш когда просматриваеш методы но не выделил ни одного метода) определён в \verb|Behavior>>sourceCodeTemplate|. Если он тебе не нравится, ты можэш изменить ево. Одним из примеров как это сделать рассмотрен в Главе \potom, Настнойка окружэния.
 
<!--
The method template (what you see when you are looking at methods but don't have a method selected) is
defined in Behavior>>sourceCodeTemplate. If you don't like it, you can change it. For one example of
how you might change it, see Chapter 31, Customizing your Environment.
-->