Why not use class fields directly?
所以我知道类和结构是数据的结构。类字段默认为私有字段,结构字段为公共字段。对于C++和EDCOX1,类似EDCOX1,0,C=1。
但是,访问这些字段的其他方法是使它们成为私有的,并使用函数/方法。像
但是为什么呢?很多人告诉我"其他人可以通过这种方式访问你的变量,所以让它们成为私有的"。我不明白,这有什么区别使他们公开,只使用他们的
您希望使用属性(getter和setter)而不是公共字段(使实例变量成为公共的)的原因有很多。其中一些是:
- 您可以允许对外部类的只读访问(通过提供getter,而不是setter)
- 您可以在访问该值时计算该值。
- 您可以在不破坏现有代码的情况下更改访问/计算值的方式。
- 您可以在不破坏现有代码的情况下更改内部表示。
- 您可以覆盖子类中的属性,这在字段中是不可能的。
- 等。
而且,使用属性并没有太多的缺点。所以利大于弊。
不同语言的答案不同。
在C++中,将属性私有化并提供GETER和SETTER方法是一个好主意,因为C++提供了常量正确性,并且不能在const对象上调用SET。
在不提供const正确性的c中,除了简单地将所有属性作为公共属性提供外,似乎没有任何意义,因为只要有一个setter,就可以随时调用它。
但是,例如,如果属性是一个容器(例如列表),该怎么办?然后,您可能只希望人们能够操作列表,而不希望将列表指针设置为新值,因此您可以这样定义属性:
1 2 3 4 5 6 | class Contrived { private List<Things> m_List = new List<Things>(); public List<Things> LIST{ get {return m_List;} } }; |
或者您可能只希望人们能够检查列表,而不希望从列表中添加或删除内容:
1 2 3 4 5 6 | class Contrived { private List<Things> m_List = new List<Things>(); public IEnumerable<Things> LIST{ get {return m_List;} } }; |
这样,我们就可以通过使用接口来伪造const的正确性,尽管在我看来,它不如拥有一种const正确的语言好。;-)实际上,在上一个示例中,我们提供了一个不能修改但内容可以是谁的列表,因此我们可以实现这样的属性(假设事物实现了IUnmodableThing):
1 2 3 4 5 6 7 8 9 10 11 12 |
很明显,这让我们比简单地公开成员属性更容易控制。那是在我们进入一个房产之前,隐瞒了事实,我们实际上,也许…哦,连接到远程数据库,通过一个插座,由定制的军用无线电携带…
一旦你意识到一个setter可以在编译时被拒绝使用(在一个常量正确的语言中),并且getter/setter或get/set(取决于语言)可以做的不仅仅是赋值或返回,那么它们可能非常强大。
那么,如果您以后想将该属性更改为数据库调用呢?这对于一个领域来说是不可能的。另外,如果您不希望从类外部而不是在类内部设置属性,该怎么办?如果您希望更改它,以便只设置非空值,该怎么办?当值更改时,您能收到通知吗?你不能用一个场和所有的getters+setter来做这些。
这种行为被广泛认为是"良好的编程方式",以便始终向类用户提供一个界面,他可以自由使用,而不必担心破坏其中的任何内容。这就是为什么要关闭类属性在类访问器方法中的更改。当改变一个字段也改变了其他一些字段并对类产生影响时,它非常有用。此外,当您试图找到某一时刻某人正在更改某个破坏某个内容的字段值时,它非常有用;)
范围界定——例如,公共的和私有的是一种告诉人们如何使用你的类的方法。
任何公共的(或C++中保护的)都是你与你的类用户的合同的一部分。
这意味着:
你不应该公开改变任何事情
您可以自由地更改任何私有的内容,因为这些内容被视为类的实现细节。
这是调用封装,允许您正确地管理对类信息的访问:封装
并不总是需要封装,但强烈建议您隐藏类内部结构并防止不适当的数据管理,例如,您可以向setter添加一些检查,如果数据是公共的,则不能防止:
1 2 3 4 5 6 7 8 9 | int SomeClass::setPointer(char *point) { if(!point) { cout <<"Trying to assign null pointer" << endl; //Or, better, throw exception return error; // Or, better, throw exception } mPointer = point; } |
这是最基本的优势,但还有其他的优势:
- 您可以在每次修改主数据时自动更新相关的控制数据(例如,每次添加新元素时的数组大小)。
- 样式:更容易维护(例如,您更改成员的类型,而您只需要在setter中添加一个强制转换,而不是修改调用此字段的所有行)
- 提高可用性
- 在某些情况下,性能更好。
- 等。
其他答案列出了许多封装的好理由。我只想补充一个最基本的原因:
- 保护类的不变量
如果你的类被设计成保持一些不变量,你不能给你的类的用户任何破坏它的方法。例如,如果您设计了一个容器,那么给用户对诸如
此外,类中数据成员的值很少是独立的,直接访问(更改值)数据很容易使对象处于不一致的状态。