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

时间:2013-09-17 09:07:28

标签: java c++ oop

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

  

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

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

谢谢!

15 个答案:

答案 0 :(得分:12)

封装提供了数据隐藏和对成员变量的更多控制。如果属性是公共的,那么任何人都可以访问它并可以为其分配任何值。但是,如果您的成员变量是私有的,并且您已为其提供了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;
         }
     }
 }

答案 1 :(得分:8)

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

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

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

宠物小便:“但如果内部变化怎么办?”没关系。您有getName函数返回std::string const&。 Getters reduce 封装,因为他们在以后更改实现时约束您的选择。

答案 2 :(得分:3)

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

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

答案 3 :(得分:3)

快速(有点愚蠢)的例子:

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;
    }    
}

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

答案 4 :(得分:3)

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

  

属性公开字段。应该(几乎总是)保留字段   私有到类并通过get和set属性访问。属性   提供一个抽象级别,允许您更改字段   不影响他们被外界访问的外部方式   用你的班级。

What is the difference between a Field and a Property in C#?

在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

答案 5 :(得分:2)

  

我认为上述案例与宣布集体成员公开的情况之间的安全级别没有任何差别。

当前的问题是:

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

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

其他原因:Why getter and setter are better than public fields in Java

答案 6 :(得分:2)

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

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

答案 7 :(得分:1)

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

答案 8 :(得分:0)

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

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

答案 9 :(得分:0)

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

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

答案 10 :(得分:0)

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

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

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

答案 11 :(得分:0)

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

  
      
  1. 封装代码更灵活,更易于根据新要求进行更改。
  2.   
  3. Java中的封装使单元测试变得容易。
  4.   
  5. Java中的封装允许您控制谁可以访问的内容。
  6.   
  7. 封装也有助于在Java中编写不可变类,这是多线程的一个很好的选择   环境。
  8.   
  9. 封装减少了模块的耦合,增加了模块内部的内聚力,因为这是一件事   被封装在一个地方。
  10.   
  11. 封装允许您更改代码的一部分而不影响代码的其他部分。
  12.   

另一个优点是

  

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

答案 12 :(得分:0)

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

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;
  }
};

Getter在API演变期间非常有用

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));
  }
};

答案 13 :(得分:0)

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

有时候一个类属性可能有多个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将提供一个接口,使该类能够使用不同的单元。

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

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

请注意,此答案来自观点,请查看this question以获取更多信息。

答案 14 :(得分:0)

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