11.9 封装 (Encapsulation)
面向对象的语言通常会提供某些手段,来区别对象的表示法以及它们给外在世界存取的介面。隐藏实现细节带来两个优点:你可以改变实现方式,而不影响对象对外的样子,而你可以保护对象在可能的危险方面被改动。隐藏细节有时候被称为封装 (encapsulated)。
虽然封装通常与面向对象编程相关联,但这两个概念其实是没相干的。你可以只拥有其一,而不需要另一个。我们已经在 108 页 (译注: 6.5 小节。)看过一个小规模的封装例子。函数 stamp
及 reset
通过共享一个计数器工作,但调用时我们不需要知道这个计数器,也保护我们不可直接修改它。
在 Common Lisp 里,包是标准的手段来区分公开及私有的信息。要限制某个东西的存取,我们将它放在另一个包里,并且针对外部介面,仅输出需要用的名字。
我们可以通过输出可被改动的名字,来封装一个槽,但不是槽的名字。举例来说,我们可以定义一个 counter
类别,以及相关的 increment
及 clear
方法如下:
(defpackage "CTR"
(:use "COMMON-LISP")
(:export "COUNTER" "INCREMENT" "CLEAR"))
(in-package ctr)
(defclass counter () ((state :initform 0)))
(defmethod increment ((c counter))
(incf (slot-value c 'state)))
(defmethod clear ((c counter))
(setf (slot-value c 'state) 0))
在这个定义下,在包外部的代码只能够创造 counter
的实例,并调用 increment
及 clear
方法,但不能够存取 state
。
如果你想要更进一步区别类的内部及外部介面,并使其不可能存取一个槽所存的值,你也可以这么做。只要在你将所有需要引用它的代码定义完,将槽的名字 unintern:
(unintern 'state)
则没有任何合法的、其它的办法,从任何包来引用到这个槽。 λ
当前内容版权归 readthedocs 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 readthedocs .