17.3 定义对象 (Defining Objects)
第一个我们需要改善的是,写一个用来创建对象的函数。我们程序表示对象以及其父类的方式,不需要给用户知道。如果我们定义一个函数来创建对象,用户将能够一个步骤就创建出一个对象,并指定其父类。我们可以在创建一个对象的同时,顺道构造优先级列表,而不是在每次当我们需要找一个属性或方法时,才花费庞大代价来重新构造。
如果我们要维护优先级列表,而不是在要用的时候再构造它们,我们需要处理列表会过时的可能性。我们的策略会是用一个列表来保存所有存在的对象,而无论何时当某些父类被改动时,重新给所有受影响的对象生成优先级列表。这代价是相当昂贵的,但由于查询比重定义父类的可能性来得高许多,我们会省下许多时间。这个改变对我们的程序的灵活性没有任何影响;我们只是将花费从频繁的操作转到不频繁的操作。
图 17.4 包含了新的代码。 λ 全局的 *objs*
会是一个包含所有当前对象的列表。函数 parents
取出一个对象的父类;相反的 (setf parents)
不仅配置一个对象的父类,也调用 make-precedence
来重新构造任何需要变动的优先级列表。这些列表与之前一样,由 precedence
来构造。
用户现在不用调用 make-hash-table
来创建对象,调用 obj
来取代, obj
一步完成创建一个新对象及定义其父类。我们也重定义了 rget
来利用保存优先级列表的好处。
(defvar *objs* nil)
(defun parents (obj) (gethash :parents obj))
(defun (setf parents) (val obj)
(prog1 (setf (gethash :parents obj) val)
(make-precedence obj)))
(defun make-precedence (obj)
(setf (gethash :preclist obj) (precedence obj))
(dolist (x *objs*)
(if (member obj (gethash :preclist x))
(setf (gethash :preclist x) (precedence x)))))
(defun obj (&rest parents)
(let ((obj (make-hash-table)))
(push obj *objs*)
(setf (parents obj) parents)
obj))
(defun rget (prop obj)
(dolist (c (gethash :preclist obj))
(multiple-value-bind (val in) (gethash prop c)
(if in (return (values val in))))))
图 17.4:创建对象
当前内容版权归 readthedocs 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 readthedocs .