使用getter和setter的私有属性有什么好处?

在面向对象的编程中,我曾经有过这个问题而且我仍然这样做:

如果我们将为其创建一个公共getter和一个公共setter ,那么将一个类成员声明为私有会有什么好处?

我认为上述案例与将类成员声明为公开案件之间的安全级别没有任何区别。

谢谢!

封装提供数据隐藏和对成员变量的更多控制。 如果属性是公共的,则任何人都可以访问它并可以为其分配任何值。 但是,如果您的成员变量是私有的,并且您已为其提供了setter。 然后,您始终可以选择在setter方法中设置一些约束,以避免设置不合逻辑的值。

例如,仅包含公共成员的类:

class MyClass { public int age; } public MyClassUser { public static void main(String args[]) { MyClass obj = new MyClass(); obj.age = -5 // not a logical value for age } } 

与私有成员和setter相同的类:

  class MyClass { private int age; public void setAge(int age) { if(age < 0) { // do not use input value and use default } else { this.age = age; } } } 

如果你的类没有不变量来维护,那么为私有数据成员编写公共getter和setter是没有意义的; 你应该只使用一个公共数据成员。

另一方面,如果您确实有不变量,那么使用setter可以允许您限制可以分配给数据成员的值。

请注意,仅仅因为您拥有数据成员并不意味着您必须为其编写任何getter或setter。

宠儿: “但如果内部变化怎么办?” 没关系。 你有一个getName函数返回一个std::string const& 。 Getters 减少了封装,因为它们会在以后更改实现时限制您的选择。

http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29

您可以稍后更改类成员的内部表示,向getter和setter添加function(例如通知Observer),所有这些都不需要更改接口(公共getter和setter)。

你的问题确实是字段和属性之间的区别。 归档通常是私有的,属性确实暴露它们。 贝娄是对SO的精彩回答的引用:

属性公开字段。 字段应该(几乎总是)保持对类的私有,并通过get和set属性进行访问。 属性提供了一个抽象级别,允许您更改字段,同时不影响使用您的类的东西访问它们的外部方式。

C#中的Field和Property之间有什么区别?

在C#中,自动属性将为您创建一个字段,而无需手动声明它:

 public Prop { get; set; } public Prop { public get; private set; } public Prop { private get; public set; } // etc, you can specify access modifier as per your need 

快速(有点傻)的例子:

 class Foo { private int age = -1; // unset value public setAge(int a) { if (a < 0) { throw new IllegalArgumentException("Invalid age "+a); } age = a; } public getAge() { if (age < 0) { throw new InvalidStateException("Age was not previously set.") } return age; } } 

简而言之:您获得了控制权,您可以确保价值是正确的。 它被称为封装。

我认为上述案例与将类成员声明为公开案件之间的安全级别没有任何区别。

当前的问题是:

1)如果要检查某些条件,设置值时该怎么办?

2)如果子类要通过ovveridng那个方法返回或设置其他内容怎么办?

其他原因: 为什么getter和setter比Java中的公共字段更好

如果你有一个数据传输对象,范围有限,并且设计上没有与之关联的逻辑,我在getter和setter中看不到值。

但是,如果您的组件可能有也可能没有与之关联的逻辑,或者可以广泛使用,那么隐藏数据存储方式的细节是有意义的。 最初可能看起来所有的getter和setter都是微不足道的,只是填满了你的课程,但随着时间的推移,你可能会向setter添加validation甚至更改getter。 例如,您可能会删除一个字段(并在将来返回一个常量),将数据存储在委托对象中或从其他字段计算值。

除了封装之外, 还要考虑一下您的setter不是简单地设置值的情况。
如果你在很多课程中使用它会怎么样? 现在你意识到你想改变它的function吗? 您必须在手动设置它的整个地方更改它。 然而,如果你有一个更年轻的生活会更容易。

访问器方法为给定字段提供单点更新。 这是有益的,因为可以通过单个方法控制对字段的validation逻辑或其他修改,而不是在整个代码库中直接访问字段。

请参阅此IBM文档,其中详细介绍了更多优势: http : //www.ibm.com/developerworks/java/library/ws-tip-why.html

如果公共getter和public setter只是为了返回私有属性的值并改变它的值,那么我认为没有区别。

但是,您正在实现封装,因此稍后您可以实现不同的行为,例如,包括对setter或只写/只读属性的参数检查。

实际上,如果你是在一个小项目上单独开发并且你不会重复使用你的代码,那它就没用了,但它主要是一个很好的习惯。

但是,在团队开发中,您可能需要对修改进行一些控制,并且可以通过getter和setter来完成。

此外,在某些类中,您将只有getter,因为setter将由构造函数或其他函数完成。

将变量声明为private称为Encapsulation in Java
在使用Java或任何面向对象的编程语言编写代码时,使用封装的几个优点是:

  1. Encapsulated Code更灵活,更易于根据新要求进行更改。
  2. Java中的封装使unit testing变得容易。
  3. Java中的封装允许您控制谁可以访问什么。
  4. 封装还有助于在Java中编写不可变类,这在multithreading环境中是一个不错的选择。
  5. 封装减少了模块的耦合并增加了模块内部的内聚力,因为所有部件都封装在一个地方。
  6. 封装允许您更改代码的一部分而不影响代码的其他部分。

还有一个优点是

在java中将变量设为私有并为它们提供getter和setter使得类与bean bean命名约定兼容

与任何封装一样:它隐藏了实现细节。 这使您可以控制访问并提供稳定的界面,即使内部更改。

Setter控制访问

 class Person //version 1.0 { std::string name; public: std::string getName() const { return name; } void setName(const std::string &newName) { if (!newName.empty()) //disallow empty names name = newName; } }; 

在API发展期间,Getter非常有用

 class Person //version 1.1 { std::string firstName; std::string lastName; public: std::string getFirstName() const { return firstName; } void setFirstName(const std::string &newFirstName) { firstName = newFirstName; } std::string getLastName() const { return lastName; } void setLastName(const std::string &newLastName) { if (!newLastName.empty()) //disallow empty last names firstName = newFirstName; } std::string getName() const { std::ostringstream s; if (!firstName.empty()) s << fistName << ' '; s << lastName; return s.str(); } void setName(const std::string &newName) { setFirstName(splitUntilLastSpace(newName)); setLastName(splitFromLastSpace(newName)); } }; 

到目前为止,我只有一件事可以补充这篇文章的优秀答案。

有时一个类属性可能有多个Getter或Setter,让我们用一个简单的简短示例来说明:

 class Angle { public: void Set(MyAngleTypedef a_value) { m_angle = a_value; } // Note the 'Radians' type void SetRadians(Radians a_value) { m_angle = ConvertRadiansToOurUnit(a_value); } // Note the 'Degrees' type void SetDegrees(Degrees a_value) { m_angle = ConvertDegreesToOurUnit(a_value); } void Get(MyAngleTypedef a_value) const { return m_angle; } // Note the 'Radians' type Radians GetRadians(Radians a_value) const { return ConvertOurUnitToRadians(m_angle); } // Note the 'Degrees' type Degrees GetDegrees(Degrees a_value) const { return ConvertOurUnitToDegrees(m_angle); } private: // Raw value of the angle in some user-defined scale. MyAngleTypedef m_angle; } 

对于您想要工作的每个单元类型,多次存储该值是没有意义的,因此Getters和Setters将提供一个接口,使该类能够使用不同的单元。

恕我直言,当一个对象包含活动属性(在分配或访问之后或之前必须做一些工作的属性)时,它必须是只有必要的Getters和Setters的类(不需要在类外访问的私有属性,显然不需要公共Getters和Setters)。

另一方面,如果一个对象只包含被动属性(在分配或访问时不需要额外工作的属性),它必须是一个struct ,因此所有属性都可以在没有Getters和Setter的情况下公开访问。

请注意,这个答案是从c ++的角度来看,请查看此问题以获取更多信息。

面向对象编程最重要的概念之一是封装。 您将数据和作用于该数据的方法封装在一起。 理想情况下,数据只能通过其相关方法访问。 并且应该通过这些方法由其他对象“查询”数据状态。 使变量公开将导致该变量直接可用于破坏封装的所有其他对象。