precedence and combination

一:precedence list

(defclass e()
  ((ce :initform "ce2" :accessor ce)
   (ef :initform "ef1" :accessor ef)
   (eb :initform "eb1" :accessor eb)))
(defclass f()
  ((cf :initform "cf2" :accessor cf)
   (ef :initform "ef2" :accessor ef)
   (fb :initform "fb1" :accessor fb)))  
(defclass c(e f)
  ((ac :initform "ac2" :accessor ac)
   (ce :initform "ce1" :accessor ce)
   (cf :initform "cf1" :accessor cf)))

(defclass h()
  ((bh :initform "bh2" :accessor bh)
   (hj :initform "hj1" :accessor hj)))
(defclass j()
  ((bj :initform "bj2" :accessor bj)
   (hj :initform "hj2" :accessor hj)))
(defclass b(h j)
  ((ab :initform "ab2" :accessor ab)
   (bh :initform "bh1" :accessor bh)
   (bj :initform "bj1" :accessor bj)
   (fb :initform "fb2" :accessor fb)
   (cf :initform "cf2" :accessor cf)))

(defclass A(c b)
  ((ac :initform "ac1" :accessor ac)
   (ab :initform "ab1" :accessor ab)))
CL-USER> (defparameter *kk* (make-instance 'a))  *KK*
CL-USER> (fb *kk*)                               "fb1"
CL-USER> (eb *kk*)                               "eb1"
CL-USER> (ce *kk*)                               "ce1"
CL-USER> (ef *kk*)                               "ef1"

precedence and combination_第1张图片

最后你会发现类之间继承的先后顺序是A->C->E->F->B->H->J->standard object->T跟我们平常说的前序查询类似。

对于类的关系比较复杂的话,你首先得画制class hierarchy,原则就是从类开始,然后向上到达直接父类,并且按照直接继承里面父类的顺序从左向右放置在一行,然后按照这种方式依次查找这些类的直接父类。

下面是子类继承的顺序原则,也就是先后顺序。

The precedence list for a class can be computed by traversing the corresponding

network as follows:

1. Start at the bottom of the network.

2. Walk upward, always taking the leftmost unexplored branch.

3. If you are about to enter a node and you notice another path entering the same node from the right, then instead of entering the node, retrace your steps until you get to a node with an unexplored path leading upward. Go back to step 2.

4. When you get to the node representing t , you're done. The order in which you first entered each node determines its place in the precedence list.

广义函数进行继承时的各种形式:

Here is a method for combine that's specialized on numbers:

(defmethod combine ((x number) (y number))

(+ x y))

Methods can even be specialized on individual objects, as determined by eql:

(defmethod combine ((x (eql 'powder)) (y (eql 'spark)))

'boom)

2standard method combination. 

This is called standard method combination. In standard method combination,

calling a generic function invokes

1. The most specific around-method, if there is one.

2. Otherwise, in order,

(a) All before-methods, from most specific to least specific.

(b) The most specific primary method.

(c) All after-methods, from least specific to most specific

The value returned is the value of the around-method (in case 1) or the value of the most specific primary method (in case 2).

CL-USER> (defclass speaker ()())
CL-USER> (defmethod speak ((s speaker) string)
	  		 (format t "~A" string))

;;;由实参匹配到最符合的
CL-USER> (speak (make-instance 'speaker) "I'm hungry")
I'm hungry
NIL

CL-USER> (defclass intellectual (speaker) ())
CL-USER> (defmethod speak :before ((i intellectual ) string)
	 		  (princ "Perhaps "))
CL-USER> (defmethod speak :after ((i intellectual) string)
			   (princ " in some sense"))

;;;利用上面的原则:首先最相关的before到最不相关,然后是最相关的主函数,最后是最不想关到最相关的after
CL-USER> (speak (make-instance 'intellectual) "I'm hungry")
Perhaps I'm hungry in some sense
NIL
CL-USER> (defmethod speak :before ((s speaker) string)
	   		(princ "I think "))

;;;始终执行一个最相关的主方法
CL-USER> (speak (make-instance 'intellectual) "I'm hungry")
Perhaps I think I'm hungry in some sense
NIL
CL-USER> (defmethod speak ((i intellectual) string)
	  		 (format t ", now"))
CL-USER> (speak (make-instance 'intellectual) "I'm hungry")
Perhaps I think , now in some sense
NIL

;;;对于主方法你可以通过call-next-method来调用,比他自己不想关的方法。
CL-USER> (defmethod speak ((i intellectual) string)
	 		  (format t ", now"))
CL-USER> (defmethod speak ((i intellectual) string)
	  		 (format t ", now")
        	 (call-next-method))
CL-USER> (speak (make-instance 'intellectual) "I'm hungry")
Perhaps I think , nowI'm hungry in some sense
NIL

;;;当遇到around关键字时,你必须有call-next-method才能够继续往下处理
CL-USER> (defclass courtier (speaker) ())
CL-USER> (defmethod speak :around ((c courtier) string)
	 		  (format t "Does the King believe that ~A? " string)
	  		  (if (eql (read) 'yes)
	       		(if (next-method-p) (call-next-method))
	      		(format t "Indeed, it is a preposterous idea.~%" 'bow)))
CL-USER> (speak (make-instance 'courtier) "kings will last")
Does the King believe that kings will last? y
Indeed, it is a preposterous idea.
NIL
CL-USER> (speak (make-instance 'courtier) "the world is round")
Does the King believe that the world is round? n
Indeed, it is a preposterous idea.
NIL
3 Method combination

有的时候你会组合所有可以应用的主方法(包括从最匹配到最不匹配)的结果,比方说你想用operator method把所有的结果组合起来,比如你定义了一个price的广义函数现在想用+把所有的可以匹配的方法的结果结合起来,也就是下面的形式,其中args表示的实参,因为你需要根据实参找到precedence list.

precedence and combination_第2张图片

我们可以在广义函数里面用关键字:method-combination来指定the type of method combination

CL-USER> (defgeneric price (x)
	  		 (:method-combination +))

现在+就作为了method combination,然后所有的price方法必须把+作为第二个参数

CL-USER> (defclass jacket () ())
CL-USER> (defclass trousers () ())
CL-USER> (defgeneric price (x)
	   		(:method-combination +))
CL-USER> (defclass suit (jacket trousers) ())
CL-USER> (defmethod price + ((jk jacket)) 350)
CL-USER> (defmethod price + ((tr trousers)) 200)
CL-USER> (price (make-instance 'suit))
550

从上面可以发现这些主函数是自动调用的,从最关联到最不关联,不需要再用call-next-method 也千万不要用,否则会报错。当时你仍旧可以用around,像前面一样,必须用call-next-method才能够调用primary method。同时注意:before :after方法不能再用了,详见下面的例子:

CL-USER> (defmethod price :around((st suit))
	   (format t "~s~%"  "around"))
CL-USER> (price (make-instance 'suit))
"around"
NIL
;;;仍旧需要around 调用call-next-method来调用主函数,
CL-USER> (defmethod price :around((st suit))
	   (format t "~s~%"  "around")
	   (call-next-method))
上面只是一个operator +的实现方式,我们还有一些其他的method combine。+  append  and  list  max  min  nconc  or  progn


总结:1:首先定义一些类,用于一些广义函数进行defmethod的时候,进行特化。

            2:定义完defmethod,然后我们根据实参,原则:如果defmethod中的特化符是我们提供的实参的类名或他的一个基类的名字。我们就认为是匹配的。

            3:根据我前面如何得到predecence list的标准进行排序。

            4:从那些applicable method中找到含有:before :after :around关键字的方法。然后根据standard method combine进行处理。 这也给我们一个信息就是所有的函数先看实参匹配,最后才是这些combine。

            5:注意其它method combine的构造方式。

你可能感兴趣的:(c,String,list,accessor)