Каков наилучший способ применения определенных значений в аргументах сообщения в smalltalk? - PullRequest
3 голосов
/ 11 декабря 2010

Я работаю над простой настольной игрой в Pharo, и у меня на доске есть метод, который добавляет объекты в ячейку. Клетки - это просто словарь точек на объектах.

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

Моя текущая попытка выглядит так:

at: aPoint put: aCell

((((aPoint x > self numberOfRows) 
    or: [aPoint x <= 0]) 
    or: [aPoint y > self numberOfColumns ]) 
    or: [aPoint y <= 0]) 
    ifTrue: [ self error:'The point must be inside the grid.' ].

self cells at: aPoint put: aCell .

Что-то вроде шуток со всеми этими паренами! Но я не могу использовать короткое замыкание or: без закрытия каждого выражения, поэтому оно оценивается как логическое значение, а не как блок (или как сообщение or:or:or:or:). Я мог бы вместо этого использовать бинарный оператор | и забыть о коротком замыкании, но это кажется неправильным.

Так, как правильно Smalltalk-иш способ справиться с этим?

Ответы [ 3 ]

6 голосов
/ 11 декабря 2010

Обычно or: вложены следующим образом:

(aPoint x > self numberOfRows 
    or: [ aPoint x <= 0  
    or: [ aPoint y > self numberOfColumns
    or: [ aPoint y <= 0 ] ] ])
        ifTrue: [ self error: 'The point must be inside the grid.' ].

Ваше вложение имеет короткий оборот, но менее эффективно из-за повторных проверок первого аргумента (проверьте байт-код, чтобы увидеть разницу).1005 *

В качестве альтернативы вы можете использовать assert: или assert:description:, который определен для Object:

self
    assert: (aPoint x > self numberOfRows 
        or: [ aPoint x <= 0  
        or: [ aPoint y > self numberOfColumns
        or: [ aPoint y <= 0 ] ] ])
    description: 'The point must be inside the grid.'
4 голосов
/ 12 декабря 2010

В любое время, когда вещи сильно вложены, пора вызывать другой метод.

isValidPoint: aPoint
  aPoint x > self numberOfRows ifTrue: [^ false].
  aPoint x <= 0 ifTrue: [^ false].
  aPoint y > self numberOfColumns ifTrue: [^ false].
  aPoint y <= 0 ifTrue: [^ false].
  ^ true.

В общем, ваши методы должны быть относительно плоскими.Если нет, время для рефакторинга.

3 голосов
/ 11 декабря 2010

Вы можете просто заполнить словарь 'ячейки' всеми точками, которые действительны в пределах диапазона, т.е. где-то в инициализации, которую вы положили:

1 to: numberOfRows do: [:y |
  1 to: numberOfCols do: [:x |
     cells at: x@y put: dummy "or nil " ] ]

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

at: aPoint put: aCell

   self cells at: aPoint ifAbsent: [ self error: 'The point must be inside the grid.' ].
   self cells at: aPoint put: aCell .

Существует также вспомогательный метод #between: and:, который вы можете использовать, чтобы минимизировать помехи в коде:

((aPoint x between: 1 and: self numCols) and: [
 aPoint y between: 1 and: self numRows ]) ifFalse: [ ... bummer ... ]
...