关于Common Lisp中广义函数,call-next-method,:around等的测试
26 Sep 2012
关于Common Lisp中广义函数,call-next-method,:around等的测试
最近正在看Common Lisp,在看到广义函数和方法组合的时候,有点晕忽忽,索性写代码测试一翻,理解如下.
直接上代码:
(defclass s () ((name :initform "S" :reader get-name)))
(defclass a (s) ((name :initform "A" :reader get-name)))
(defclass b (s) ((name :initform "B" :reader get-name)))
(defclass me (a b) ((name :initform "Me" :reader get-name)))
;定义四个类,S是上帝,A是爸爸,B是妈妈,Me是我。
(defgeneric say-hello (s) (:documentation "Say hello")); 广义函数,传入一个参数。
(defmethod say-hello ((s s))
(format t "S:main say-hello! ~A~%" (get-name s))); 上帝主方法
(defmethod say-hello :around ((s s))
(format t "S:around say-hello! ~A~%" (get-name s))
(call-next-method)); 上帝around, 想一想去掉(call-next-method)会怎样
(defmethod say-hello :before ((s s))
(format t "S:before say-hello! ~A~%" (get-name s))); 上帝before
(defmethod say-hello :after ((s s))
(format t "S:after say-hello! ~A~%" (get-name s))); 上帝after
(say-hello (make-instance 's));想想输出什么
(format t "=======================~%")
(say-hello (make-instance 'a));想想输出什么
(format t "=======================~%")
(say-hello (make-instance 'me));想想输出什么
(format t "=======================~%")
(defmethod say-hello ((s a))
(format t "A:main say-hello! ~A~%" (get-name s))
(call-next-method)); 爸爸主方法, ,想一想去掉(call-next-method)会怎样
(defmethod say-hello :around ((s a))
(format t "A:around say-hello! ~A~%" (get-name s))
(call-next-method)); 爸爸around, ,想一想去掉(call-next-method)会怎样
(defmethod say-hello :before ((s a))
(format t "A:before say-hello! ~A~%" (get-name s))); 爸爸before
(defmethod say-hello :after ((s a))
(format t "A:after say-hello! ~A~%" (get-name s))); 爸爸after
(say-hello (make-instance 'a));想想输出什么
(format t "=======================~%")
(say-hello (make-instance 'me));想想输出什么
(format t "=======================~%")
(defmethod say-hello ((s b))
(format t "B:main say-hello! ~A~%" (get-name s))
(call-next-method)); 妈妈主方法, ,想一想去掉(call-next-method)会怎样
(defmethod say-hello :around ((s b))
(format t "B:around say-hello! ~A~%" (get-name s))
(call-next-method)); 妈妈around, ,想一想去掉(call-next-method)会怎样
(defmethod say-hello :before ((s b))
(format t "B:before say-hello! ~A~%" (get-name s))); 妈妈before
(defmethod say-hello :after ((s b))
(format t "B:after say-hello! ~A~%" (get-name s))); 妈妈after
(say-hello (make-instance 'b));想想输出什么
(format t "=======================~%")
(say-hello (make-instance 'me));想想输出什么
(format t "=======================~%")
(defmethod say-hello ((s me))
(format t "Me:main say-hello! ~A~%" (get-name s))
(call-next-method)); 我主方法, ,想一想去掉(call-next-method)会怎样
(defmethod say-hello :around ((s me))
(format t "Me:around say-hello! ~A~%" (get-name s))
(call-next-method)); 我around, ,想一想去掉(call-next-method)会怎样
(defmethod say-hello :before ((s me))
(format t "Me:before say-hello! ~A~%" (get-name s))); 我before
(defmethod say-hello :after ((s me))
(format t "Me:after say-hello! ~A~%" (get-name s))); 我after
(say-hello (make-instance 'Me));想想输出什么
(format t "=======================~%")
代码完成,现在解释一下:
类的继承关心是这样的(多重继承):
S
A B
Me
广义函数只有一个,每个类都实现了该广义函数,并且:around, :before, :after都有,并且在主方法和around方法里都调用(call-next-method)。那么对于这个调用:
(say-hello (make-instance 'Me))执行情况如何呢?
首先要进行主方法排序: 根据最近优先原则,依次是:我,爸爸,妈妈,上帝。
所以整个顺序如下(16个方法):
1. around在所有之前。around应该最先执行,依次是:我around,爸爸around,妈妈around,上帝around. 若中间某个around没有(call-next-method),那么就此结束。
2. before在主方法之前:依次是:我before, 爸爸before,妈妈before, 上帝before.
3. 主方法:依次是:我主方法,爸爸主方法,妈妈主方法,上帝主方法。若中间某个主方法没有(call-next-method),那么将不继续调用下面的主方法,而是直接调用之后的after方法。
4. after在主方法之后且倒序:依次是:上帝after, 妈妈after, 爸爸after, 我after。
注意1:若某一步的辅助方法(或主方法,主方法特殊,见注意2)不存在,则只跳过该方法,(15个方法)。
注意2:不可以只有辅助方法,而没有主方法。主方法是可以继承的,就是说如果上帝有主方法,而我们没有主方法,却有辅助方法是可以的。如果上帝没有主方法,却有辅助方法是不行的。
最后完整输出如下:
S:around say-hello! S
S:before say-hello! S
S:main say-hello! S
S:after say-hello! S
=======================
S:around say-hello! A
S:before say-hello! A
S:main say-hello! A
S:after say-hello! A
=======================
S:around say-hello! Me
S:before say-hello! Me
S:main say-hello! Me
S:after say-hello! Me
=======================
A:around say-hello! A
S:around say-hello! A
A:before say-hello! A
S:before say-hello! A
A:main say-hello! A
S:main say-hello! A
S:after say-hello! A
A:after say-hello! A
=======================
A:around say-hello! Me
S:around say-hello! Me
A:before say-hello! Me
S:before say-hello! Me
A:main say-hello! Me
S:main say-hello! Me
S:after say-hello! Me
A:after say-hello! Me
=======================
B:around say-hello! B
S:around say-hello! B
B:before say-hello! B
S:before say-hello! B
B:main say-hello! B
S:main say-hello! B
S:after say-hello! B
B:after say-hello! B
=======================
A:around say-hello! Me
B:around say-hello! Me
S:around say-hello! Me
A:before say-hello! Me
B:before say-hello! Me
S:before say-hello! Me
A:main say-hello! Me
B:main say-hello! Me
S:main say-hello! Me
S:after say-hello! Me
B:after say-hello! Me
A:after say-hello! Me
=======================
Me:around say-hello! Me
A:around say-hello! Me
B:around say-hello! Me
S:around say-hello! Me
Me:before say-hello! Me
A:before say-hello! Me
B:before say-hello! Me
S:before say-hello! Me
Me:main say-hello! Me
A:main say-hello! Me
B:main say-hello! Me
S:main say-hello! Me
S:after say-hello! Me
B:after say-hello! Me
A:after say-hello! Me
Me:after say-hello! Me
=======================
(完)