【问题标题】:A setter with logic in javajava中带有逻辑的setter
【发布时间】:2014-03-25 13:30:58
【问题描述】:

考虑在 Java 中存储一些文本的 Message 对象。

public class Message {

    private String text;
    private boolean containsDigit;

    public Message() {
        //constructor
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public boolean isContainsDigit() {
        return containsDigit;
    }

}

这是一个持久化对象。

我对在构造函数中设置数据没有任何问题,但是可以在创建对象之后设置 Message 的文本字段,并且在设置文本时,此后 containsDigit 字段也应该是可查询的。 显而易见的方法是在 setter 中:

public void setText(String text) {
     // presume existence of method to check for digit
     if(text.containsDigit())
         this.containsDigit = true;

     this.text = text;
}

但这是否会导致由于 setter 方法中的逻辑而导致任何“最佳实践”警报响起?

有人会建议替代实现吗?

编辑

我可能应该补充一点,containsDigit 字段是必需的,因为该对象是持久的,因此可以随后查询 containsDigit 字段。 此外,在使用 Spring/Hibernate 引擎的应用程序中,在重新读取/写入对象时会不断调用此设置器,因此也想知道它的实用性/效率。

【问题讨论】:

  • 嗯,这就是使用 seter 和 getter 的全部目的 - 以便封装和防止直接访问可能不一致的字段。
  • 这就是二传手的重点:)
  • 对于“这是获取者和设置者的重点”的人。还有另一种说法,“专家”说他们应该仅用作评估者,因此纯粹是为了访问变量的值。否则他们可以“隐藏”代码中的问题/错误。
  • 你能指出对这个叙述的引用吗?我怀疑它适用于不属于您的问题的不变性。

标签: java oop setter getter-setter


【解决方案1】:

您的情况正是使用 setter 和 getter 的原因。如果不允许您在 setter 中使用逻辑,那么您不妨直接访问这些字段!

【讨论】:

  • 是的,但这就是日常企业软件中发生的事情 - getter 和 setter 只是 Java bean 的生成方法,逻辑为 0,期望 setter 只是设置一个值,当您刚刚编写的单元测试失败,因为 setter 中有一些“隐藏”逻辑..
【解决方案2】:

这可能不是最佳实践,但有时生活比最佳实践更强大。

可能更好的方法是删除 field containsDigit 并将您添加到 setter 的逻辑移动到 isContainsDigit()

public class Message {
    private final static Pattern d = Pattern.compile("\\d");
    private String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public boolean isContainsDigit() {
        return text == null ? false : d.matcher(text).find();
    }

}

【讨论】:

  • 这是 Java 标准最佳实践中的首选解决方案。以防万一有另一种方式可以修改text,此解决方案将防止您手动设置containsDigit
  • @DesertIvy,你说得对,但这更好,因为这个字段不能与文本分开设置。它应该根据定义自动计算。
  • 记住这是一个持久化对象。因此需要有一个 containsDigit 成员变量来满足 ORM 要求,因此,除非我遗漏了什么,否则它会排除这个建议。
  • @dre,持久性不是造成糟糕设计或数据重复的原因。例如,JPA 支持 @PostLoad@PreUpdate 注释,有助于自动启动字段。在这种情况下,甚至不需要这样做:我们不必保留标志isConainsDigit(),除非有基于此标志的数据库查询。
  • @AlexR 首先,请记住,这只是一个假设示例,我在这里的原因是寻找好的设计建议。 @PostLoad@PreUpdate 的想法正是我正在寻找的那种建议,除了它们仅限于 JPA 实现。哦,假设需要查询标志。
【解决方案3】:

实现方法public boolean isContainsDigit()如下:

public boolean isContainsDigit() {
    return getText().containsDigit();
}

这样您就不必让它们保持同步,而不必一次又一次地重新评估它。另一方面,如果您不需要这样做,则永远不要对代码进行性能优化。如果两个线程同时访问 setText() 和 isContainsDigit() 方法,则它们属于竞争条件。如果你想解决这个问题,也许你必须同步它们。

【讨论】:

  • 这不仅是对文本查询数字的方法的要求,结果还需要持久化在数据库中,因此成员变量是强制性的。
【解决方案4】:

@dre - 真的太奇怪了。除了争论某种设计的优雅或纯粹性之外,Saint 链接的任何链接都没有与您的问题有很大的区别。如果你有一个“setter”,那么重点是能够用一些逻辑来围绕变量的设置,以确保变量得到正确设置,同时考虑到类中其他属性存在的依赖关系,前提是出现这种需要。如果“setter”将是“纯”的,那么摆脱它们并将变量公开。 Robert Martin 的“干净代码”一书中实际上可能有一些内容明确地谈到了 occam 剃刀原则或简约原则。也许这个链接有帮助:http://effectivesoftwaredesign.com/2013/08/05/simplicity-in-software-design-kiss-yagni-and-occams-razor/。最后应该注意的是,完全不建议将属性设为公开,因为返回并将属性设为私有是一场噩梦。我重申-首先选择使您​​的类不可变,并且所有成员属性都是私有的。如果该类的用户尖叫,请他们说明为什么需要对其进行变异。一旦考虑到他们的理由,请创建一个 setter,不要公开变量。这应该作为一组设计规则。 Hibernate 或 JPA 应该与此设计决策无关。

要使具有许多参数的类不可变,请使用构建器模式 - When would you use the Builder Pattern?

【讨论】:

  • “争论某种设计的优雅或纯粹”!这就是我要问的,这样的论点有什么实质内容吗?您似乎认为我在争论或试图证明将成员变量公开的决定是合理的。当然不!我认为这个问题在这一点上已经为我解答了,如果你不应该为二传手添加逻辑,那么拥有一个二传手有什么意义呢?当然,我提到 hibernate 是因为 hibernate 需要提供一个 setter(尽管我认为你可以将其设为私有)。
  • @dre - 不,我不这么认为,我知道 ;-) 计算机科学家都知道:-)
  • “计算机科学家无所不知”。可以的,我可以接受。 :-)
【解决方案5】:

我可以说这是“足够好”。但是,如果您想完全遵循面向对象的设计,您将实现类似于事件onTextChange 的东西,只要 set 更改文本就会触发该事件。另一方面,您将为此事件实现处理程序,该处理程序将更新containsDigit 字段。对于您的简单示例,这确实是不必要的,但如果您希望将来在 setText() 中添加新逻辑,您可以考虑这一点。

【讨论】:

  • 我不同意。 isContainsDigit() 是派生信息,所以只要你不需要缓存结果,我认为发出事件是过度设计的。
  • 我写道,在这种特殊情况下,我不会这样做。即使 isContainsDigit 是派生信息,它也会被缓存,所以如果我们假设这个 es 的计算很昂贵,我仍然会使用这种方法。有时每次获取都计算这个不是很好。在这种情况下是可以的,但我们只是在考虑示例,我们可以考虑所有可能性。
  • 当然,如果你必须缓存,因为某些计算非常广泛,我必须同意通知设计。观察者或发出事件是最明显的事情。
  • 必须同意@Harmlezz,这似乎有点矫枉过正,进一步不必要的功能抽象。
猜你喜欢
  • 1970-01-01
  • 2018-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多