Kotlin封装
什么是封装?
封装指的是将数据与操作这些数据的方法绑定在一起,并限制对某些组件的直接访问。
在使用面向对象语言进行编程时,我们完全控制对象的修改。对象本身不会自行改变;它总是需要一个“理由”来发生变化,这个理由通常是你对它执行了某个操作。举个例子来帮助理解:想象一面墙的颜色。你觉得哪种方式更合理,是直接去修改颜色的属性值,还是调用一个 paintTheWall()
方法?显然第二种方式更清晰——因为墙不会自己改变颜色!
建议务必小心处理对象的数据,因为直接访问对象内部数据就像打开时钟机芯来拨动齿轮设置时间一样——很容易搞坏它! 与其自己动手,不如使用制造商设计好的旋钮进行调整。由此可见,把关键的实现细节隐藏起来,对普通用户来说是更安全、合理的做法。
(类比:通过外部旋钮调整时钟时间,而不是打开齿轮结构)
就像钟表匠一样,我们需要隐藏对象内部的实现细节。我们需要一种机制,能够在不影响用户的前提下更改代码。对象的方法可以保持稳定,而属性本身可以在内部发生变化。
这听起来像是修改对象的一项难题,但或许有一个更简单的解决方案:
Getter 和 Setter 方法
成为程序员就像是工程师。你可以创建一个外部无法更改的数据字段,也可以设计一些带有保护机制的方法来限制对数据的修改。对于那些绝对不能从外部更改的数据,我们可以完全不提供任何修改方法。这样可以防止用户执行危险或不可预测的操作。
最简单且最常见的做法是提供访问数据的方法,同时保留对数据修改的控制权。这些方法被称为getter(获取器)和 setter(设置器)。虽然有些人认为 setter 会导致对象可以被随意修改,但通过这些方法有很多好处。使用 setter 方法时,我们可以:
-
要求必须通过特定操作(而不是直接访问)来修改数据;
-
在设置数据前进行验证,确保新数据是合法的,不会破坏对象的完整性;
-
如果数据不符合要求,我们可以阻止操作的发生。
领域特定方法(Domain-specific methods)
假设你正在开发一个 Clock
(时钟)类。用户可以通过 setTime()
方法设置时间,但如果他们希望更细致地修改时间,你可以添加以下方法:
-
addHour()
-
addMinute()
-
addSeconds()
这样就可以更贴近现实中对时钟的操作方式。
另外,用户可能想要调整时区,而不是去单独设置小时、分钟。此时你可以设计一个 changeTimezone()
方法——它会更清晰、更合理。用户只需要传入一个时区或城市,方法内部完成所有调整逻辑。
(类比:使用“时区调整”方法而非逐项设置时间)
数据保护
保护对象内部数据的方法因编程语言而异。一些语言提供了关键字来限制类字段的访问权限;另一些语言则使用命名约定或名称改写(Name mangling) 技术。你应该查阅你所使用语言的文档来了解如何正确实现封装。
-
有些语言使用诸如
public
、private
、protected
的关键词来设置字段的可见性。通过这些关键词,你可以明确限定变量在什么范围内可以访问。 -
另一种方式是命名约定。例如规定所有以大写字母开头的变量为公共变量,而以小写开头的变量只能在类内部访问。
-
Public(公共)访问意味着该属性可以直接通过名称访问。
-
Name mangling(名称改写) 是将字段名在外部访问时改写的一种原则。比如你在类中定义了一个属性
minutes
,而在类外只能通过do_not_use_these_minutes
来访问它。这并不是真正的访问限制,但它发出了一个 “请勿使用” 的警告。 -
如果你希望某个字段只能读取而不能修改,你应该只提供 getter 方法。
总结
面向对象的编程强调通过方法与对象交互。你可以使用 getter、setter 和 领域特定方法来访问或修改类的属性。同时,你可以通过编程语言提供的规则(如访问修饰符、命名规则等)来控制属性的可见性范围。
使用这些手段可以隐藏对象的内部实现细节,从而使代码更容易维护,也更加安全稳定。