在面向对象编程中,我曾经有过这个问题,但我仍然这样做:
如果我们为它创建一个公共 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&
. Getter减少了封装,因为它们在以后更改实现时限制了您的选择。
快速(有点傻)的例子:
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;
}
}
简而言之:您获得了控制权,并且可以确保值是正确的。这叫做封装。
http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29
您可以稍后更改类成员的内部表示,向 getter 和 setter 添加功能(例如通知观察者),所有这些都无需更改接口(公共 getter 和 setter)。
您的问题确实是字段和属性之间的区别。归档通常是私有的,并且属性会公开它们。贝娄是对 SO 的精彩回答的引述:
属性公开字段。字段应该(几乎总是)对类保持私有,并通过 get 和 set 属性访问。属性提供了一个抽象级别,允许您更改字段,同时不影响使用您的类的事物访问它们的外部方式。
在 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
我认为上述案例与将类成员声明为公共的案例在安全级别上没有任何区别。
直接的问题是:
1)如果你想检查一些条件,同时设置值怎么办?
2)如果子类想要通过 ovveridng 该方法返回或设置其他东西怎么办?
如果您有一个范围有限的数据传输对象,并且按照设计它应该没有与之关联的逻辑,那么我在 getter 和 setter 中看不到任何值。
但是,如果您有一个组件可能有也可能没有与之关联的一些逻辑,或者它可以被广泛使用,那么隐藏数据存储方式的细节是有意义的。最初看起来所有的 getter 和 setter 都是微不足道的,只是填满了你的类,但随着时间的推移,你可能会向 setter 添加验证,甚至更改 getter。例如,您可能会删除一个字段(并在将来返回一个常量),将数据存储在委托对象中或从其他字段计算值。
除了封装之外,考虑一下你的设置器不是简单地设置一个值的情况。
如果您在许多课程中使用它怎么办?现在你意识到你想改变它的功能了吗?您必须在手动设置它的整个地方进行更改。而如果你有一个二传手的生活会更容易。
与任何封装一样:它隐藏了实现细节。即使内部结构发生变化,这也允许您控制访问并提供稳定的界面。
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;
}
};
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));
}
};
面向对象编程最重要的概念之一是封装。您将数据和作用于该数据的方法封装在一起。理想情况下,数据应仅通过其相关方法访问。并且数据的状态应该被其他对象通过这些方法“查询”。将变量公开将导致该变量可直接用于所有其他对象,从而破坏封装。
访问器方法为给定字段提供单点更新。这是有益的,因为可以通过单一方法控制验证逻辑或对字段的其他修改,而不是在整个代码库中直接访问该字段。
请参阅此 IBM 文档,其中详细介绍了更多好处:http ://www.ibm.com/developerworks/java/library/ws-tip-why.html
如果公共 getter 和公共 setter 只是返回私有属性的值并更改其值,那么我认为没有区别。
但是,您正在实现封装,因此稍后您可以实现不同的行为,例如,包括对 setter 或只写/只读属性的参数检查。
实际上,如果你在一个小项目上单独开发并且你不会重用你的代码,那有点没用,但它主要是一个好习惯。
但是,在团队开发中,您可能需要对修改进行一些控制,您可以通过 getter 和 setter 来实现。
此外,在某些类中,您将只有 getter,因为 setter 将由构造函数或通过其他一些函数完成。
将变量声明为private
称为 as Encapsulation in Java
。
以下是在使用 Java 或任何面向对象的编程语言编写代码时使用封装的几个优点:
- 封装代码更灵活,更容易根据新要求进行更改。
- Java 中的封装使单元测试变得容易。
- Java 中的封装允许您控制谁可以访问什么。
- 封装还有助于在 Java 中编写不可变类,这在多线程环境中是一个不错的选择。
- 封装减少了模块的耦合并增加了模块内部的凝聚力,因为一个事物的所有部分都封装在一个地方。
- 封装允许您更改代码的一部分而不影响代码的其他部分。
另一个优点是
在 Java 中将变量设为私有并为它们提供 getter 和 setter 使您的类兼容 Java bean 命名约定
到目前为止,我只有一件事可以添加到这篇文章的优秀答案中。
有时一个类属性可能有多个 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
只有基本的 Getter 和 Setter(显然不需要在类外访问的私有属性)不需要公共的 Getter 和 Setter)。
另一方面,如果一个对象只包含被动属性(分配或访问时不需要额外工作的属性),它必须是 a struct
,因此他的所有属性都可以在没有 Getter 和 Setter 的情况下公开访问。