如果我们在实体类的getter和setter中添加逻辑是不是设计不好

Saw*_*mar 2 java oop pojo getter-setter

爪哇 8

我有一个 POJO 类:

class User {
    private String name;
    private String password;

    //... Getters / Setters ...
}
Run Code Online (Sandbox Code Playgroud)

我将用作实体类。

在 getter/setter for 中password,我想添加解密/加密逻辑。

public String getPassword() {
    return EncryptionFactory.decryption(password);
}

public void setPassword(String password) {
    this.password = EncryptionFactory.encryption(password);
}
Run Code Online (Sandbox Code Playgroud)

EncryptionFactory是一个加密/解密 a 的实用程序类String

我的问题是

根据通用 Java 编码指南,如果我添加更改密码的逻辑,它是否破坏了设计或设计不良?

在使用它时,我从我的教授那里得到了糟糕的设计反馈。

Vin*_*igh 5

来自关于 mutatorswiki 文章

通常一个 setter 伴随着一个 getter(也称为访问器),它返回私有成员变量的值

由于 getter 旨在提供对私有字段值的访问权限,因此它会违反最小惊讶原则:可能会抛出异常,EncrpytionFactory在某些时候实现的 impl for可能会变得无效,等等......当开发人员期望简单地访问一个值时.

您是否认为这种糟糕的设计取决于您的设计标准有多严格。确定的最佳方法是查看缺点:

  • 无法获取加密密码
  • 强制使用String明文密码来存储密码(因为会setPassword自动加密)
  • EncrpytionFactory在包含的类型中引入依赖get/setPassword

所以在你的具体情况下,这是糟糕的设计。

尽管在某些情况下,某些开发人员可能更喜欢它。例如,如果你有一个Person#getAge() : int但使用一个Date属性来管理这个人的年龄:

class Person {
    private Date dateOfBirth;

    public int getAge() {
        Date now = ...; //grab date/time right now
        int age = ...; //calculate age using dateOfBirth and now

        return age;
    }
Run Code Online (Sandbox Code Playgroud)

有些人会争辩说计算应该解耦,或者getAge应该命名为calculateAge

来自维基文章:

相反,访问器允许从内部变量合成有用的数据表示,同时保持它们的结构封装和隐藏在外部模块中。货币 getAmount 访问器可以从具有隐藏货币参数定义的小数位数的数字变量构建字符串。


在你的情况下,还有更多需要担心的。

你真的想解密密码,比如,有什么理由吗?假设您要维护安全性,则有更安全的方法来维护密码。

任何时候您想将输入的密码与存储的密码进行比较,只需加密输入的密码并将结果与​​存储的密码进行比较。

如果有人想要“恢复”他们的密码,那么以纯文本形式向用户发送他们的密码会带来安全风险。这就是为什么大型企业要求您在忘记密码时重置密码。


假设您想保留解密。

每次有人打电话时你真的需要解密getPassword()吗?如果有人想要加密的值怎么办?

您应该将解密与访问分开。看看你已经有一个EncryptionFactory

User user = ...;
String encryptedPassword = user.getPassword();
String decryptedPassword = EncryptionFactory.decryption(encryptedPassword);
Run Code Online (Sandbox Code Playgroud)

您的密码实际上应该只有少数几次被解密(有些人可能认为它不应该在内存中解密)。重点是,它应该是完全可选的。

密码应设置为已加密:

String encryptedPassword = EncryptionFactory.encrpytion(...);

User user = ...;
user.setPassword(encryptedPassword);
Run Code Online (Sandbox Code Playgroud)

它应该可以以加密形式访问。你永远不应该强迫这样的安全风险(解密密码),让它成为可选的。

最后,如果您必须公开解密的getPassword替代方案,则应将其重命名为decryptPassword()

public String decryptPassword() {
    return EncrpytionFactory.decryption(getPassword());
}
Run Code Online (Sandbox Code Playgroud)

尽管这会在User(或您使用的任何类型)和EncryptionFactory.

您应该真正深入研究安全方面。您不应该将解密的密码维护为String如果除了用户之外没有人知道密码这是最安全的