“控制反转”在Lisp中被广泛使用。这是非常简单的,因为函数和闭包是一等对象。
依赖注入很简单。类和函数可以通过符号和一等类进行配置。
通常在Common Lisp中不需要IoC或DI的“框架”,因为许多功能用于配置和参数化应用程序和库已经内置。
“一等”意味着某些东西可以存储在变量中,作为参数传递或作为结果返回。
在像Common Lisp这样的语言中,函数和类是一等对象。此外,为了通过延迟绑定进行解耦,您可以使用符号作为它们的名称。Common Lisp对象系统知道元类和符号作为类的名称。甚至通用函数和方法也是对象,并且具有元类。
如果“concurrent-secure-server”是一个类,“default-response”是一个函数,您可以执行以下操作:
(make-instance 'web-services
:server-class 'concurrent-secure-server
:default-response-function 'default-reponse)
以上使用符号作为类和函数的名称。如果该函数有新版本,Web服务可能会在以后调用新版本。
或者:
(make-instance 'web-services
:server-class (find-class 'concurrent-secure-server)
:default-response-function #'default-reponse)
在上述情况中,我们传递了类对象和函数对象。
在Common Lisp中,软件模块可以拥有全局变量,您可以使用正确的信息进行设置:
(defvar *default-server-class* 'concurrent-secure-server)
或者您可以像下面这样将它们设置在插槽中。
(defclass server-object ()
((default-response-function
:initarg :default-response-function
:initform *server-default-response-function*)))
(defvar *my-server*
(make-instance 'server-object
:default-response-function 'my-default-response-function))
您甚至可以在配置阶段创建对象并稍后更改其类。 Common Lisp对象系统允许您更改类并更新现有对象。
如果您创建实例,您可以尽可能灵活:
就像这样:
(let ((my-class 'foo-class)
(my-args `(:response-function ',*some-reponse-function)))
(apply #'make-instance my-class my-args))
有时你会看到在运行时计算这些参数列表的Lisp库。
另一个可以在运行时配置Lisp应用程序的方法是通过通用函数。通用函数允许使用:before、:after和:around方法,甚至允许您自定义调用方案。因此,通过使用从其他类和混合类继承的自己的类,通用函数得到重新配置。这就像内置了面向方面编程的基本机制。
对于那些对这些更高级的面向对象概念感兴趣的人,施乐帕克(Xerox PARC)有一些文献,在创建CLOS时研究了这些问题。当时它被称为“开放实现”:
http://www2.parc.com/csl/groups/sda/publications.shtml(原始链接,现在已失效)
存档:
https://web.archive.org/web/20110906111530/http://www2.parc.com/csl/groups/sda/publications.shtml
在开放实现方法中,模块允许其客户端单独控制模块自身的实现策略。这使得客户端能够根据自己的需求定制模块的实现策略,有效地使模块更具可重用性,客户端代码更简单。该控制通过一个精心设计的辅助接口提供给客户端。
您不需要的一件事:XML。通用Lisp是自己的配置语言。编写扩展以实现更轻松的配置可以通过宏完成。这些配置的加载可以通过
LOAD
轻松完成。