在smalltalk中重构方法
我是Smalltalk(Squeak)的新用户(实际上是在课程中学习)。 我有一个方法来检查一个矩形是否等于一个给定的矩形,如下所示:在smalltalk中重构方法,smalltalk,squeak,Smalltalk,Squeak,我是Smalltalk(Squeak)的新用户(实际上是在课程中学习)。 我有一个方法来检查一个矩形是否等于一个给定的矩形,如下所示: isEqual:givenRec self a = givenRec a ifTrue: [ self b = givenRec b ifTrue: [ ^true ]. ^false ]. self b = givenRec a if
isEqual:givenRec
self a = givenRec a
ifTrue: [
self b = givenRec b
ifTrue: [
^true
].
^false
].
self b = givenRec a
ifTrue: [
self a = givenRec b
ifTrue: [
^true
].
^false
].
^false
我的问题是——有没有更好的方法来写这篇文章?让它更紧凑
还有-为什么我不能引用a
,它是带有自内方法的instanceVariableNames?
谢谢你的帮助
编辑:
这就是类的定义方式:
MyShape subclass: #MyTriangle
instanceVariableNames: 'a b c'
classVariableNames: ''
poolDictionaries: ''
category: 'Ex2'
MyShape
只是从Object
派生而来,没有任何东西。你可以让它更紧凑,是的
首先,除了#ifFalse:
之外,还有#ifFalse:
和#ifFalse:
,大致具有if not--then和if--then--else的效果
但是,我们已经有了逻辑AND条件,为什么不使用它呢:
isEqual: givenRec
(self a = givenRec a and: [self b = givenRec b])
ifTrue: [^ true].
(self b = givenRec a and: [self a = givenRec b])
ifTrue: [^ true].
^false
使用#如果正确:如果错误:
isEqual: givenRec
(self a = givenRec a and: [self b = givenRec b])
ifTrue: [^ true]
ifFalse: [^ (self b = givenRec a and: [self a = givenRec b])]
此外,我们可以围绕整个语句进行返回:
isEqual: givenRec
^ (self a = givenRec a and: [self b = givenRec b])
ifTrue: [true]
ifFalse: [self b = givenRec a and: [self a = givenRec b]]
但是ifTrue:[true]
有点多余,让我们使用或:
isEqual: givenRec
^ (self a = givenRec a and: [self b = givenRec b]) or:
[self b = givenRec a and: [self a = givenRec b]]
又好又甜,我们也很容易看到逻辑结构。
(请注意,我与常见的格式样式不同,以指出这两个逻辑表达式的异同)
我们现在只有一个返回^
,没有#如果是:…
对于实例变量问题: 当您像以前一样在类中定义一些实例变量时,您可以在代码中使用它们来访问它们:
Object subclass: #Contoso
instanceVariableNames: 'things'
classVariableNames: ''
poolDictionaries: ''
category: 'Examples'
但通常,最好通过getter和setter(通常称为访问器)引用实例变量。您必须手动编写它们,或使用浏览器中类的第二个上下文菜单(通过“更多…”)的“创建inst var访问器”菜单项:
这将生成表单的访问器方法
thing
^ thing
你可以在其他类似的方法中使用它们
isThingPlusThreeSameAs: anObject
^ self thing + 3 = anObject
我会把这个方法写成
equals: aTriangle
a = aTriangle a ifFalse: [^false].
b = aTriangle b ifFalse: [^false].
^c = aTriangle c
顺便注意一下,我使用的是选择器#equals:
,而不是#isEqual:
,因为后者的英文读起来不太好(如果是#isEqualTo:
,那就好了,但是#equals:
更短)
我想在这里补充的另一点是,您可以重新定义#=
,而不是添加新的比较选择器。但是,在这种情况下,您必须注意以下几点:
= aTriangle
self class = aTriangle class ifFalse: [^false].
a = aTriangle a ifFalse: [^false].
b = aTriangle b ifFalse: [^false].
^c = aTriangle c
进行类检查的原因是确保#=
是健壮的,即它不会发出消息NotUnderstanding
异常的信号。另一件事是,每次你(重新)定义=
时,你也应该(重新)定义#hash
,这样无论何时t1=t2
。比如说
hash
^(a hash + b hash + c hash) hash
请注意,这个关于#hash
的建议并不是最好的,但这里不是讨论编写好的#hash
函数问题的地方
更新
这是我的版本,当顺序无关紧要时
equals: aTriangle
| sides |
self = aTriangle ifTrue: [^true].
sides := Set with: a with: b with: c.
(sides includes: aTriangle a) ifFalse: [^false].
(sides includes: aTriangle b) ifFalse: [^false].
^(sides includes: aTriangle c)
第一个比较是加速该方法,避免在顺序相同时设置
。您可能不应该这样编写,但在某些情况下,元编程这是有用的
isEqual: givenRec
#(a b c) do: [ :selector |
(self perform: selector) = (givenRec perform: selector) ifFalse: [
^false]].
^true
谢谢,我编辑了我的问题-添加了类定义另一个问题@Tobias-如何在屏幕上绘制一个矩形,给定其两条边的长度?因此,您的类看起来很好,现在这取决于您用于比较的代码~~请为实例变量问题提出一个新问题~~编辑我的答案为绘制一个矩形,请提出一个新问题,这样更容易回答这是一个链接,当一个顶点不同时,您不能使用提前返回,因为他希望忽略顺序来比较顶点,所以(a,b,c)=(c,b,a)我不喜欢有两个不同的相等概念,一个是在#=中有有序顶点,另一个是在#equalsTo中有集合:…在#equals中,集合是用1而不是a定义的vertex@CarlosE.Ferro固定的。谢谢
equals: aTriangle
| sides |
self = aTriangle ifTrue: [^true].
sides := Set with: a with: b with: c.
(sides includes: aTriangle a) ifFalse: [^false].
(sides includes: aTriangle b) ifFalse: [^false].
^(sides includes: aTriangle c)
isEqual: givenRec
#(a b c) do: [ :selector |
(self perform: selector) = (givenRec perform: selector) ifFalse: [
^false]].
^true