View on GitHub

Yoy-wiw

A website on lisp.

Download this project as a .zip file Download this project as a tar.gz file

关于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

=======================

(完)