1. 当其他部分的代码想要执行对象的某些操作时,可以借助对象向外部提供的接口完成操作,从而对象也保持了自身的内部状态不会被外部代码随意修改(对象的内部状态保持了私有性),而外部代码只能通过对象所提供的接口访问和修改对象的内部状态,不能直接访问和修改对象的内部状态。
2. 封装定义:保持对象内部状态的私有性、明确划分对象的公共接口和内部状态,这些特性称之为封装(encapsulation)。
3. 封装的好处:当程序员需要修改一个对象的某个操作时,程序员只需要修改对象对应方法的内部实现即可,而不需要在所有代码中找出该方法的所有实现,并逐一修改。某种意义上来说,封装在对象内部和对象外部设立了一种特别的“防火墙”。
4. 例如,学生只有在二年级以后才能学习弓箭课,我们可以将学生的 year
属性暴露给外部,从而外部代码可以通过检查学生的 year
属性来确认该学生是否可以选修该课程。
if (student.year > 1) {
// 允许学生选修弓箭课
}
①问题:如果我们决定修改选修弓箭课的标准(例如需要家长的同意),我们需要在选课系统的代码中修改每一个相关的部分,这是相当麻烦的。
②解决:如果我们向 Student
类中添加一个 canStudyArchery()
方法(用于检查学生是否能够选修弓箭课),那么相应代码的实现逻辑就会集中在一个地方:
class Student : extends Person
properties
year
constructor
Student(name, year)
methods
introduceSelf()
canStudyArchery() { return this.year > 1 }
if (student.canStudyArchery()) {
// 允许学生选修弓箭课课
}
如果我们要修改选修弓箭课的规则,我们只需要更新 Student
类中的相应方法即可,而其他地方的代码无需修改,整个系统仍旧可以正常工作。
5. 在许多面向对象编程语言中,可以使用 private
关键字标记对象的私有部分,也就是外部代码无法直接访问的部分。如果一个属性在被标记为 private
的情况下,外部代码依旧尝试访问该属性,计算机会抛出一个错误。
class Student : extends Person
properties
private year
constructor
Student(name, year)
methods
introduceSelf()
canStudyArchery() { return this.year > 1 }
student = new Student('Weber', 1)
student.year // 错误:'year'是学生类的私有属性
6. 也有部分语言并不采用强制措施阻止外部代码访问对象的私有属性,在这种情况下,程序员们通常会采用一些约定俗称的命名方式来标记对象的私有部分,例如将以下划线开头的变量名看作是对象的私有部分。