我试图在Common Lisp CLOS中找到典型菱形继承(钻石问题)问题的解决方案。编码 :
(defclass C1.0 () ... )
(defclass C2.1 (C1.0) ...)
(defclass C2.2 (C1.0) ...)
(defclass C3.0 (C2.1 C2.2) ...)
(defmethod m1 ((obj C1.0)) ...)
(defmethod m1 ((obj C2.1)) ...)
(defmethod m1 ((obj C2.2)) ...)
(defmethod m1 ((obj C3.0))
; Here I want to call the C2.2 version of
; m1
...)
还要假设C1.0,C2.1和C2.2的代码在我无权访问的库中,因此我无法在此进行任何修改。 Furthur,假设其他一些类也将从C2.2派生,并且可能不希望调用m1的C2.2版本,因此我不能使用
:before
真正向C2.2添加任何内容。使用call-next-method
将调用C2.1版本。只是为了澄清,这是如何在Python中解决它:
class C1_0 :
def m1 (self) : ...
class C2_1 (C1_0) :
def m1 (self) : ...
class C2_2 (C1_0) :
def m1 (self) : ...
class C3_0 (C2_1, C2_2) :
def m1 (self) :
C2_2.m1 (self) # <-- This is the solution
...
最佳答案
如果您要调用类的特定方法,那么您将无法达到CLOS的目的。还请注意,CLOS比这更笼统,因为它不仅支持多重继承,而且还支持多重分派(dispatch)。调度可以处理多个参数。因此,方法不属于类,并且方法的继承不是基于类继承,而是基于方法组合(通常使用类继承以某种方式对方法进行排序)。
让我们看看分派(dispatch)两个参数的方法:
(defmethod m1 ((obj1 C1.0) (obj2 C1.0)) ...)
(defmethod m1 ((obj1 C2.1) (obj2 C1.0)) ...)
(defmethod m1 ((obj1 C2.2) (obj2 C3.0)) ...)
(defmethod m1 ((obj1 C3.0) (obj2 C3.0)) ...)
请注意,我们谈论的是标准方法组合,当您调用泛型函数时,通常会调用最特定的主要方法。在CLOS中,标准方法组合中的适用方法可以通过
call-next-method
调用下一个方法。这是直接调用继承功能的常用机制(还有:before
,:after
和:around
方法可以提供继承功能)。但是,另一个(简单)方法组合(例如
+
,progn
或and
)又如何呢?在+
的情况下,将调用所有适用的方法并添加结果。然后我们有如下方法:
(defmethod m1 + ((obj1 C1.0) (obj2 C1.0)) 1)
(defmethod m1 + ((obj1 C2.1) (obj2 C1.0)) 2)
(defmethod m1 + ((obj1 C2.2) (obj2 C3.0)) 10)
(defmethod m1 + ((obj1 C3.0) (obj2 C3.0)) 20)
像这样的简单方法组合并不经常在应用程序或库中使用。 CLOS还为用户指定的复杂方法组合提供了一种方法(例如:用户可以在CLOS中实现按契约(Contract)功能进行设计)。
您可以在CLOS中解决它:您可以访问泛型函数的特定方法并调用其方法函数,但这很少使用,并且已经是元级功能。您还可以编写自己的方法组合,在其中可以提供更复杂的调用方法。但这也很困难。
因此,仅当您考虑面向类的对象系统并尝试使用CLOS时才考虑CLOS中的“菱形继承(钻石问题)”才有意义。但是,CLOS并没有解决菱形继承(钻石问题)的方法。 CLOS通过将相同的插槽合并为一个插槽来避免使用该插槽。 CLOS通过提供一种将方法组织到通用类中并通过首先通过方法组合将它们组装在一起的方法来调用它们,从而避免了对方法的使用。
关于inheritance - 菱形继承(钻石问题)和Common Lisp对象系统,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27074151/