从哲学上讲,我应该从 getter 还是 setter 中调用方法?

Philosophically speaking, should I call a method from within a getter or setter?

在最近一次快乐的开发团队聚会中,我们提出了一个要讨论的五件事的议程,然后很快就变成了对议程上没有的事情的激烈辩论。

我们正在通读一些代码,这时我们团队中一位经验丰富的开发人员对以下代码片段提出了担忧。 (开发栈是TypeScript/Angular4),但这与讨论无关:

get someIsValidProperty(): Number {
    return this.ruleService.runSomeRule();
}

在这种情况下,模板表单上的一个字段引用了 someIsValidProperty。在模板中,看起来像是对一些 属性 的简单调用,指示有效或无效状态。在这方面,争论是它看起来简洁直观,并且最终通过某种逻辑调用,我们决定搬出并建立依赖关系。

但是从单元测试的角度来看,它看起来很奇怪。正如我们断言正在使用预期值调用 ruleService 的模拟。感觉 getter 实际上应该是一个方法,并且在客户端调用上下文中会更加清晰。此外,另一个论点是 getters 和 setter 应该以某种方式真正公开 class/object 本身的内部状态,而不是交给其他东西。

公平地说,我们很有礼貌,但存在分歧,并决定'去看看其他团队在做什么并复制它们®'

现在,当我回到我的办公桌时,我期待着 google,并找到一大堆狡猾的论点,以进一步 enrage 授权各自的营地。

但是什么都没有(我能在我自己短暂的注意力范围内找到)。

所以,我的问题是,是否有任何理由,无论是哲学上的还是其他方面的,为什么我们应该避免从 getters 或 setter 中调用方法?本着避免基于意见的讨论的精神,一些清晰的想法和论点将不胜感激。

我认为这最终是一个非常审美和实用的决定,而不是一般的通用指南。属性是语法糖,可以保存五个字符,你可以随心所欲地使用它。我个人认为,从客户的角度来看,将对象 "appears to belong" 变成 属性 是公平的。然后,实现可以采用任意数量的形状(来自对象中的实际字段、私有字段的 getter 或对另一个对象的方法的调用)。这对于制作假货非常实用。但是,当我说 "it's fair" 时,我并不一定意味着我一直都是这样做的。团队开发的大项目应该优先考虑一致性和生产力。我认为也可以公平地说属性可能难以测试,因此不应包含任何需要测试的逻辑。

可以从两方面考虑,做出妥协。从模板设计者(无论是否编码者)的角度来看,属性使事情变得 "neater",这并不像听起来那么微不足道,因为更整洁的模板更易于维护。从测试人员的角度来看,属性可能会进行 "worse-looking" 测试(再次降低可维护性)。你有一个从 "no properties" 到 "anything can go in properties" 的连续体,团队可以决定在每个人都感到舒服的地方放一条线,但重要的是,这是明确的指南(例如 "do not put logic into properties" 或 "remember to test properties because they may contain logic").

一个可能的 "best of both worlds" 解决方案是使用像 "properties can only get/set a private field or call a getter/setter method" 这样的规则。所以你有:

getSomeIsValidProperty(): Number {
    return this.ruleService.runSomeRule();
}

get someIsValidProperty(): Number {
    return this.getSomeIsValidProperty();
}

所以你有整洁的模板和 good-looking 测试。当然,缺点是你有一些冗余代码(即使永远不需要测试属性)。