【问题标题】:A real life example of public properties being bad公共财产不好的真实例子
【发布时间】:2016-06-20 15:11:49
【问题描述】:

我无数次读到一个类的公共属性是一个主要的错误,但我不明白为什么在没有被转换的数据上输入/输出。

我会写的例子

public class Employee
{
    public String firstName;
    public String lastName;
    private int ssn = 0;
    public boolean setSsn(String s)
    {
        //makes perfect sense why something like an ssn would use a getter setter
        //some code to validate ssn
        if(!validSsn(s)){
            ssn = 0; 
            return false;
        }
        ssn = raw;
        return true;
    }
    public String getSsn()
    {
        return ssn;
    }
    private boolean validSsn(String s)
    {
        //validation goes here
        retrun val;
    }

    //I don't understand why I should make firstName private
    // and then write
    public void setFirstName(String s)
    {
        firstName = s;
    }
    public String getFirstName(String s)
    {
        return firstName;
    }       
}

请提供一个可能导致问题的场景并且请具体说明,而不是“因为当其他人使用您的代码时它会导致问题”为什么?为什么会引起问题。提前感谢建设性的批评和详细的回答:D

【问题讨论】:

  • 如果您想在设置 firstName 时对其进行错误检查怎么办?或者设置好后锁定。您的 set 方法中没有任何逻辑,因此您的示例不需要它,但在某些情况下您可能需要该逻辑。
  • employee.firstName = "\n";
  • 不是公共属性不好,而是公共 fields 打破了封装,允许在类不知情的情况下更改数据。如果您不关心字段中的值,那没什么大不了的。但是,如果您依赖它们存在或在其他方法中具有某些值,则无法通过字段强制执行此操作。
  • 除了@FelixCastor 所说的,您可能不需要检查字段值...现在。但是,如果您需要在以后的版本中检查它怎么办? :)
  • @assylias - 今天的普通设置器明天可以更改,而不会影响外部调用者。公共领域不能。它们在 Java 中是不等价的。

标签: java oop conventions


【解决方案1】:

假设您的代码已投入生产。我编写了一个前端,它使用您的 Employee 类直接访问 firstNamelastName

6 个月过去了,现在有一个新的业务需求,您需要在名称字段中添加验证。

你要在哪里添加它?您将不得不将字段设为私有并添加 set 方法,这将迫使我和其他所有人使用您的代码重新编写我们的应用程序。

如果您一开始就正确封装了这些数据,我们所要做的就是使用新版本的库和您的代码重新编译。

【讨论】:

  • 谢谢,这回答了我的问题。但是,您是否不必捕获新的异常?当然,您会避免更改“setFirstName()”语句,但如果名称无效,您将如何处理?为什么 Java 不能有 C# 风格的 get/set :'(
  • 您可以添加回退机制,例如在出现错误时不设置字段。无论回退是什么,使用 setter 和 getter 都可以提供更大的灵活性,因为您实际上隐藏了类中的逻辑并提供了一个干净而漂亮的接口。公共字段很丑。
  • @JesseAdam 由于您已经在 ssn 字段上进行了验证,我假设我已经设置了一个通用的“捕获异常、显示错误、重新提示用户”机制。不能保证我不必再次接触代码,但适当的封装只需很少的努力即可在您的代码中加入相当多的面向未来的功能。
  • @Hafnernuss 缺乏未来的证据?当然,但你不敢称它们为丑陋的!每次我想要简单的数据时调用一个方法真的很难看。雇员.setFirstName("戴夫"); --我可以习惯它 vs employee.firstName = "Dave"; --还是觉得更干净|||| print(employee.firstName) -- 干净,最小 vs print(employee.getFirstName()) -- 这是我讨厌的
  • @JesseAdam 嗯,这是个人品味的问题,我会给你。就个人而言,在使用 C++ 时,有时我编写的数据结构只是数据的容器。在这种情况下,我会采用你的方法,主要是因为我很懒而且速度很快。但是一旦类实际上对参数做了一些事情,我就会使用 getter 和 setter,原因是上面提到的。而且,老实说,通过 get/set 访问数据在代码大小上并不比直接使用字段更费力。
猜你喜欢
  • 2020-12-17
  • 1970-01-01
  • 2011-03-13
  • 2018-05-18
  • 2011-12-21
  • 2016-02-13
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多