在smalltalk中对消息参数强制执行某些值的最佳方法是什么?

时间:2010-12-10 22:25:58

标签: smalltalk pharo

我正在研究Pharo中的简单棋盘游戏,我在我的棋盘上有一个方法可以将对象添加到单元格中。单元格只是对象上的点的字典。

作为该方法的一部分,我想强制Point应该大于零,但小于板的宽度和高度,换句话说,它应该实际上在板上。这样做的最佳方式是什么?

我目前的尝试是这样的:

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 .

与所有那些parens的lisp-y!但是我不能使用短路or:而不关闭每个表达式,因此它评估为布尔而不是块(或or:or:or:or:消息)。我可以使用二进制运算符|代替和for-go短路,但这似乎不对。

那么正确的Smalltalk-ish方法处理这个问题是什么?

3 个答案:

答案 0 :(得分:6)

通常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.' ].

由于第一个参数的重复测试(检查字节码以查看差异),您的嵌套是短路但效率较低。

备选方案,您可以使用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.'

答案 1 :(得分:4)

任何时候都是严重嵌套的东西,是时候调用另一种方法了。

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.

一般来说,您的方法应该相对平坦。如果没有,那就重构一下。

答案 2 :(得分:3)

您可以简单地使用在该范围内有效的所有点预填充'cells'字典,即在初始化的某个位置:

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:和:,您可以使用它来最小化代码混乱:

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