【问题标题】:Refactoring a method in smalltalk在 smalltalk 中重构方法
【发布时间】:2016-04-09 08:30:49
【问题描述】:

我是 Smalltalk (Squeak) 的新用户(实际上是在课程中学习)。 我有一种方法可以检查一个矩形是否等于给定的矩形,如下所示:

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 ,它是带有 self 内部方法的 instanceVariableNames? 感谢您的帮助!

编辑:

这是类的定义方式:

MyShape subclass: #MyTriangle
    instanceVariableNames: 'a b c'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Ex2'

MyShape 只是从Object 派生而来,什么都没有。

【问题讨论】:

    标签: smalltalk squeak


    【解决方案1】:

    你可以让它更紧凑,是的。

    首先,除了#ifTrue:之外,还有#ifFalse:#ifTrue:ifFalse:,大致有if-not--then和if--then--else的效果。

    而且,我们已经有了一个逻辑与条件,所以为什么不使用它:

    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
    

    #ifTrue:ifFalse:

    isEqual: givenRec
    
        (self a = givenRec a and: [self b = givenRec b])
            ifTrue: [^ true]
            ifFalse: [^ (self b = givenRec a and: [self a = givenRec b])]
    

    此外,我们可以围绕整个语句进行 return:

    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]有点多余,我们还是用#or:

    isEqual: givenRec
    
        ^ (self a = givenRec a and: [self b = givenRec b]) or: 
          [self b = givenRec a and: [self a = givenRec b]]
    

    很好,很好,我们也很容易看到逻辑结构。 (请注意,我不同于常见的格式样式,以指出两个逻辑表达式的异同。

    我们现在只有一个返回^,没有#ifTrue:…


    对于实例变量问题:

    当你像你一样在类中定义一些实例变量时,你可以在你的代码中使用它们来访问它们:

    Object subclass: #Contoso
        instanceVariableNames: 'things'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Examples'
    
    isThingPlusThreeSameAs: anObject
    
        ^ thing + 3 = anObject
    

    但通常情况下,最好通过 getterssetters 引用实例变量,通常称为 accessors。您必须手动编写它们或使用浏览器中类的 second 上下文菜单(通过“更多...”)的“create inst var accessor”菜单项:

    这将生成表单的访问器方法

    thing
    
        ^ thing
    
    thing: anObject
    
        thing := anObject
    

    你可以在其他类似的方法中使用它们

    isThingPlusThreeSameAs: anObject
    
        ^ self thing + 3 = anObject
    

    【讨论】:

    • 谢谢,我编辑了我的问题 - 添加了类定义
    • 另一个问题@Tobias - 给定两条边的长度,我如何在屏幕上绘制一个矩形?
    • 所以你的类看起来不错,现在它真的取决于你用于比较的代码。 ~~请为实例变量问题提出一个新问题~~编辑我的答案
    • 啊,画一个矩形,请提出一个新问题,这样更容易回答
    【解决方案2】:

    你可能不应该这样写,但在某些情况下元编程很有用

    isEqual: givenRec
      #(a b c) do: [ :selector |
        (self perform: selector) = (givenRec perform: selector) ifFalse: [
          ^false]].
      ^true
    

    【讨论】:

      【解决方案3】:

      我会把方法写成

      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
      

      类检查的原因是确保#= 是健壮的,即它不会发出MessageNotUnderstood 异常的信号。另一件事是,每次您(重新)定义#= 时,您还应该(重新)定义#hash,使得t1 hash = t2 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)
      

      第一个比较是在顺序相同时加快避免Set的方法。

      【讨论】:

      • 不能在一个顶点不同的情况下使用early return,因为他想比较顶点忽略顺序,所以(a, b, c) = (c, b, a)
      • 我不喜欢有两种不同的相等概念,一种在#= 中具有有序顶点,另一种在#equalsTo: 中具有集合。
      • 在#equals中,集合定义为1而不是顶点
      • @CarlosE.Ferro 已修复。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-20
      • 2017-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多