У меня возникает соблазн воспользоваться вашим вопросом и ответом и немного рассказать о знаниях, относящихся к фольклору Smalltalk (о котором вы, возможно, уже знаете).
По мере того, как мы прогрессируем в использовании Smalltalk, мы, вероятно, заметим, что класс Array
начинает играть уменьшающую роль в наших моделях. Это почему? Потому что требуется время, чтобы выяснить, какие объекты будут производить наши модели; баланс между слишком многими и слишком немногими является деликатным вопросом, в большинстве своем не знающим в начале.
Массивы и их состав представляют собой удобные структуры данных. Однако они решают проблему организации данных за счет борьбы с ними. Если клиенту такой структуры необходимо знать, как данные хранятся в качестве предварительного условия для действий с ними, то парадигма сообщения становится семантически бездействующей.
Давайте представим матричный объект. Есть несколько способов сохранить их записи: одномерный массив, массив строк, массив столбцов, словарь (разреженных) ненулевых записей, структура tri angular, если известно, что матрицы симметричны / антисимметричный / эрмитовой и многое другое для особых случаев. Конечно, это разнообразие не имеет смысла для рассматриваемой проблемы, и в любом случае было бы плохой идеей проводить время, рассматривая наиболее общий подход: В Smalltalk общность достигается в сообщении, а не в хранилище.
Независимо от внутренней организации данных, наши объекты всегда должны предлагать протоколы, которые не зависят от базовой структуры. Возвращаясь к примеру матрицы, даже если наша первоначальная организация представляет собой массив строк, объект матрицы должен работать одинаково, независимо от того, являются ли строки массивами или более сложными объектами vector , которые также используются для других целей. Это означает, что при кодировании внутреннего доступа к записи (i,j)
мы должны делать вид, что не знаем класс строки i
, а только сообщение для доступа к ее j
-ому элементу. Что-то вроде
atRow: i column: j
| row |
row := self row: i.
^row at: j
Здесь мы не предполагаем, что row
является Array
; мы только предполагаем, что он понимает сообщение at:
, которое является наименьшим, что мы можем предположить при разговоре со строковым объектом, независимо от его фактической природы. Конечно, этот код хорош только в предположении, что строки не воссоздаются на лету, как если бы наш класс хранился вместо коллекций столбцов. Но это нормально, в противном случае нам нужно будет только добавить другой класс и переопределить этот и некоторые другие сообщения низкого уровня .
В любом случае, идея состоит в том, чтобы отложить как можно больше любые явные знания о внутренней организации, чтобы она ограничивалась несколькими личными сообщениями. Один из способов проверить, что мы применяем эту хорошую практику, - убедиться, что ни один код низкого уровня не повторяется в двух или более методах. Например, использование приведенного выше сообщения row:
перемещает низкоуровневый код от atRow:column:
, откладывая его на другой, который имеет смысл для (идеального) матричного протокола.
Этот пример иллюстрирует важный момент: с подозрением относиться к любому коду, который должен составлять два at:
сообщения. И - почему бы не - насладиться красотой отсутствия необходимости объявлять типы.