是否有必要在POJO中使用getter和setter

时间:2011-09-17 14:55:50

标签: java coding-style

我一直在阅读干净的代码簿,该代码书指出该类不应暴露其数据的内部状态,只应暴露该行为。如果一个非常简单和愚蠢的java bean暴露了getter和setter的内部状态,是否值得删除它们并使私有成员公开?或者只是将该类视为数据结构?

10 个答案:

答案 0 :(得分:19)

我不这么认为。它取决于对象的生命周期及其“暴露”(外部修改)。

如果您只是将它用作数据结构,那么以安全的方式(最终)公开字段听起来就足够了:

public class Person {
    public final String firstName;
    public final String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

答案 1 :(得分:8)

术语POJO旨在将类与JavaBeans或任何其他约定区分开来。因此,根据定义,POJO不需要做任何事情。

  

我一直在阅读干净的代码簿,该代码簿指出该类不应公开其数据的内部状态,只应暴露该行为。

这称为封装和良好的原则。

  

如果一个非常简单和愚蠢的java bean暴露了getter和setter的内部状态,是否值得删除它们并使私有成员公开?

这是另一种方法。有些项目可能会禁止这种方法,而其他项目可能会鼓励这种做法就个人而言,我赞成这种方法用于以某种方式封装的类,例如他们是当地的包裹。

有观点认为,某天某些方面您的课程可能会有其他要求,并且更改“API”将是不可能的。这违背了YAGNI原则,并且很少证明是这种情况,并且当它确实比添加许多不做任何事情的方法成本低得多时。

但是,情况并非总是如此,如果您不使用访问器方法,则应考虑如果您以后必须更改它对项目的影响。在任何地方使用访问器方法意味着您永远不必担心这一点。

总之,如果您非常确定存取方法毫无意义,以后添加它们不会有问题,我会说您应该使用您的判断。但是,如果您不确定将来是否会出现问题,或者您不想担心它,请使用访问器方法。

答案 2 :(得分:4)

POJO的定义并不强制要求getter / setter。

实验上,我没有在当前项目中使用getter和setter。

我采取的方法就是这个:

  

除非必要,否则不要提供getter / setter。

到目前为止,我没有找到我真正需要获取/设置的情况。

有些朋友告诉我:“如果将来需要xyz,获取/设置是有帮助的”;我的答复是:在将来 - 我需要这样做,我会提供吸气剂和制定者;我不想期待任何事情。

有些人可能提出的关于封装的异议并不是真正有效的:提供getter和setter以同样的方式打破封装,再加上你有额外的(无用的)代码行。虫子也可能存在于吸气剂和杀手中。

这是一个非平凡的域类的例子:

public class SSHKey implements IsSerializable {
    public Long id;
    public Long userId;
    public String type;
    public String bits;
    public String fingerprint;
    public String comment;

    @SuppressWarnings("unused")
    private SSHKey() { // required by gwt-rpc
    }

    public SSHKey(String text) throws InvalidSSHKeyException {
        Ensure.that(text != null, new InvalidSSHKeyException("Invalid Key"));
        text = text.trim();
        String[] parts = text.split(" ", 3);
        Ensure.that(parts.length >= 2,
                new InvalidSSHKeyException("Invalid Key"));

        type = getType(parts);
        Ensure.that(type.equals("ssh-rsa") || type.equals("ssh-dss"),
                new InvalidSSHKeyException(
                        "Key must start with 'ssh-rsa' or 'ssh-dss'"));
        bits = getBits(parts);
        comment = getComment(parts);
    }

    private String getBits(String[] parts) {
        return parts[1];
    }

    private String getComment(String[] parts) {
        if (parts.length == 3)
            return parts[2];
        return type + " " + bits.substring(0, min(15, bits.length())) + "...";
    }

    private String getType(String[] parts) {
        return parts[0];
    }
}

构造函数负责验证和准备可管理的数据。因此,该逻辑不需要在setter / getter中。

如果几年前我被公众成员看作对象,我可能不会喜欢他们;也许我现在做错了,但我正在试验,到目前为止还可以。

此外,您需要考虑您的类是否设计为扩展(因此,预见未来是需求的一部分),并且您希望您的对象是不可变的。那些你只能用get / set做的事情。

如果您的对象必须不可变,并且您可以避免使用空构造函数,则可以将“final”添加到成员实例btw。 不幸的是,我必须添加IsSerializable(类似于java.io.Serializable)和一个空构造函数,因为gwt需要这样做。所以,你可以告诉我“你看到了吗?你需要吸气剂是一个二传手”;不太确定。

有一些jdbc框架可以促进使用公共字段btw,例如http://iciql.com 这并不意味着这个项目是正确的,但有些人正在考虑它。

我认为getter / setter的需求主要是文化的。

答案 3 :(得分:2)

使成员可访问的问题是你不再从课堂内控制它们。

假设你让Car.speed可以访问。现在,在你编程的任何地方都可以有一些参考。现在,如果您想确保速度永远不会设置为负值(或者为了使线程安全而使更改同步),您必须:

  • 在可以访问速度的所有点中,重写程序以添加控件。并希望将来改变该计划的每个人都记得这样做。

  • 再次将该成员设为私有,创建getter和setter方法,并重写程序以使用它们。

最好习惯从头开始编写getter和setter。如今,无论如何,大多数IDE会自动为您完成。

答案 4 :(得分:2)

对此的规范回答是:您不知道您的简单数据结构将来是否会如此简单。它可能比你现在预期的发展得更多。也许有可能,你很快就会想要那个bean中的一些“值改变”的观察者。使用getter和setter方法,您可以在以后简单地执行此操作,而无需更改现有的代码库。

getter / setter的另一个优点是:如果在罗马,确实喜欢罗马人...这意味着在这种情况下:许多通用框架期望 getter / setter。如果您不想从一开始就统治所有这些有用的框架,那么请您和您的同事帮忙,并简单地实现标准的getter /和setter。

答案 5 :(得分:2)

仅当您在一个超出您控制范围的库中公开某个类时。

如果您确实发布了这样的库,Uniform Access Principle要求您应该使用getter和setter,以便以后能够更改底层实现,而无需客户端更改其代码。 Java没有为您提供其他机制。

如果您在自己的系统中使用此类,则不需要:您的IDE可以轻松封装公共字段并在一个安全步骤中更新其所有用法。在这种情况下,简洁性会赢,并且在您需要封装的时候不会丢失任何内容。

答案 6 :(得分:1)

我认为使用getter和setter是个好主意,除非你有非常具体的速度/内存/效率要求或非常简单的对象。

一个很好的例子是Point,它可能更好,更有效地公开它的.x.y变量。

也就是说,如果你突然在setter中需要一些逻辑,那么改变一些成员变量的可见性并引入getter和setter甚至是大型代码库实际上并不是一件大事。

答案 7 :(得分:1)

JavaBeans需要getter和setter。 POJO没有,无论如何这有其好处

getter和setter的目标是实现封装,它管理对象的内部状态。这允许您在应用程序实现后在应用程序中添加或更改业务规则,只更改getter或setter代码,例如,如果您有一个只允许超过3个字符的文本字段可以在将其分配给属性之前进行检查并且抛出一个异常,其他不这样做的原因是,如果你可能想要改变实现或更改变量名或类似的东西。如果该字段是可公开访问和可修改的,则无法强制执行此操作 无论如何,你可以使用你的IDE来生成setter和getter。

如果您正在开发一个简单的应用程序,可以推荐,如果您的应用程序很复杂,并且不建议进行维护。

答案 8 :(得分:1)

对于数据类型对象,如POJO / PODS / JavaBean,在python中你只有公共成员
您可以设置这些并轻松获取,而无需生成样板设置器和getter代码(在java中,这些样板代码通常(98%)公开内部私有标记,如问题中所述)
在python中,如果你需要与getter进行交互,那么你只需要为此目的定义额外的代码 语言水平清洁有效

在java中,他们选择了IDE开发而不是更改基本java,参见JavaBean,例如多大了,java 1.0.2多大了...... JDK 1。0(1996年1月23日)
EJB规范最初由IBM于1997年开发,后来于1999年由Sun Microsystems(EJB 1.0和1.1)采用
所以只要忍受它,使用setter getter,因为这些是由java环境强制执行的

答案 9 :(得分:0)

这就是@Peter Lawrey解释封装的真实情况。

只有一个注意事项:当您使用复杂对象时(例如在ORM项目中的域模型中),当您拥有非简单Java类型的属性时,更为重要。例如:

public class Father {
   private List childs = new ArrayList();
   public Father() {
      // ...
   }
   private List getChilds() { 
      return this.childs;   
   }
   public void setChilds(List newChilds) { 
      this.childs = newChilds; 
   }
}

public class Child {
   private String name;
   // ...
   private String getName() { 
      return this.name;   
   }
   public void setName(String newName) { 
      this.name = newName; 
   }
}

如果您将一个属性(例如childs类中的Father属性)公开为公开属性,则无法确定代码的哪个部分正在设置或更改您的公开属性(在这种情况下,例如,向Child添加新的Father,甚至更改现有name的{​​{1}}。在该示例中,只有Child对象可以检索Father内容,并且所有其他类都可以使用其setter来更改它。