直接使用类属性

时间:2010-08-19 16:46:31

标签: java oop

我听说直接使用类属性并不是一个好主意,而是使用setter和getter。有人可以告诉我为什么吗?

6 个答案:

答案 0 :(得分:6)

有趣的是,关于这个主题的维基百科文章提供了很好的指导:http://en.wikipedia.org/wiki/Accessor

简而言之,类应该使用mutator方法(getter,setter等)在私有存储之前验证输入。这样做可确保始终可以依赖代码中的其他位置。

相比之下,如果属性是全球可用的,任何人都可以修改它。例如,如果您有一个需要特定格式的字符串,并且有人添加了一个不正确的值,则可能会导致错误。

答案 1 :(得分:5)

简而言之,如果您编写接口(包含getter和setter到私有字段)的代码,那么您可以换出符合该接口的任何对象。对象字段的外部引用意味着外部用户知道实现。这会在对象的使用者和对象的实现之间产生耦合,在这种情况下这是一件坏事。

今天您的name字段可能会存储为String,但明年您可能希望将其更新为某种更有趣的类型,或者从其他地方或任何其他地方获取信息......谁知道?使用字段会阻止您这样做。使用访问器可以让您根据需要更改实现。这是一个比你想象的更重要的原则。

您可能会感兴趣:[{3}}

答案 2 :(得分:1)

这取决于;对于类中的简单更改(bool成员),更改它可能更快。如果它稍微复杂一些(MyDate),那么你可能想要实现一些验证。

大多数人将成员数据保密,因此必须使用get / set或方法来修改类外的数据。

答案 3 :(得分:1)

这是一项惯例,虽然是强有力的。

JavaBean规范使用它来解决Java没有属性的问题。

它允许表达只读/只写或读写属性的意图。

在setter中放置断点以查看属性无法更改的原因非常方便。

如前所述,接口不能包含属性,但可以定义访问器。

有时你会想要创建'虚拟'属性,经典的例子是复数,你有属性x和y,并通过setter和getters中的计算提供mod和angle。

许多API依靠此约定通过反射推断出你的类的含义。

所有IDE现在都可以自动生成它们,这样它们就不会像过去那样伤害我的手指。

答案 4 :(得分:1)

有两个经典原因要禁止外部访问字段(属性)。这些通常在介绍性面向对象编程类中讨论。

  1. 如果基础数据是私有的,您可以自由更改类中的实现。例如,假设您将复数存储为实部和虚部。然后你决定要改变它来存储Z和theta(幅度和角度)。如果您公开了字段,那么更改将破坏与其交互的任何类。如果您使用过访问器,则可以根据Z和theta实现getReal()和getImaginary(),而不会破坏任何内容。
  2. 您可以向getter和(特别是)setter添加其他操作。例如,您可以跟踪对字段进行了多少更改,或者更新与其同步的另一个字段,但前提是您已强制任何想要更改字段的类通过访问者来执行此操作。在公共领域,你没有机会做这些事情。

答案 5 :(得分:1)

真正归结为Java不尊重Uniform Access Principle。也就是说,用于改变字段值的客户端代码(例如obj.field = newValue)与用于调用setter的代码(例如obj.setField(newValue))非常不同。

如果您从公共字段开始,后来确定您确实需要私有成员(例如,添加验证或更改成员的基础实现),则所有客户端代码都将中断。因此,如果任何机会您需要访问者提供的其他功能,则需要使用setter而不是public字段。最终结果是许多不必要的代码:

public class Person {
   private String _firstName;
   private String _lastName;

   public Person(String firstName, String lastName) {
      _firstName = firstName;
      _lastName = lastName;
   }

   public String getFirstName() {
      return _firstName;
   }

   public void setFirstName(String name) {
      _firstName = name;
   }

   public String getLastName() {
      return _lastName;
   }

   public void setLastName(String name) {
      _lastName = name;
   }
}

在尊重UAP的语言中,例如Scala,使用公共字段而不是getter / setter是很常见的。例如,Scala中的上述类是:

class Person(var firstName: String, var lastName: String)

// example client code:
val p = new Person("John", "Smith");
p.lastName = "Brown";

如果我决定需要验证,我可以将其替换为:

class Person(firstName: String, lastName: String)
   private var _firstName = validate(firstName);
   private var _lastName = validate(lastName);

   // getters
   def firstName: String = _firstName
   def lastName: String = _lastName

   // setters
   def firstName_=(name: String): Unit = { 
      _firstName = validate(name); 
   }

   def lastName_=(name: String): Unit = { 
      _lastName = validate(name); 
   }

   // validation
   @throws(classOf[IllegalArgumentException])
   private def validate(name: String): String = { 
      // ... validation code ...
      name
   }
}

// and client code doesn't break!
val p = new Person("John", "Smith");
p.lastName = "Brown";