我想用多用户界面后端(例如文本和图形)编写代码,因此它们很容易切换.我的方法是使用CLOS:
(defgeneric draw-user-interface (argument ui)
(:documentation "Present the user interface")
(:method (argument (ui (eql :tui)))
(format t "Textual user interface! (~A)" argument))
(:method (argument (ui (eql :gui)))
(format t "Graphical user interface! (~A)" argument)))
Run Code Online (Sandbox Code Playgroud)
这种方法乍一看似乎没问题,但它有一些缺点.为了简化调用,我定义了将在每个函数调用中使用的参数ui-type,以简化后端的切换,但是在使用高阶函数时会导致问题:
(defparameter *ui-type* :tui
"Preferred user interface type")
(draw-user-interface 3 *ui-type*)
;;; I can't use the following due to the `ui' argument:
;(mapcar #'draw-user-interface '(1 2 3))
;;; Instead I have to write this
(mapcar #'(lambda (arg)
(draw-user-interface arg *ui-type*))
'(1 2 3))
;; or this
(mapcar #'draw-user-interface
'(1 2 3)
(make-list 3 :initial-element *ui-type*))
;; The another approach would be defining a function
(defun draw-user-interface* (argument)
(draw-user-interface argument *ui-type*))
;; and calling mapcar
(mapcar #'draw-user-interface* '(1 2 3))
Run Code Online (Sandbox Code Playgroud)
如果采用这种方法,我们可以将通用函数命名为%draw-user-interface,将包装函数命名为draw-user-interface.
它是有效的方法还是有更简单的方法?问题是为相同的功能提供不同的后端,而不一定是用户界面.
另一个用例可能是一种情况,当我有许多相同算法的实现(针对速度,内存消耗等优化)时,我想以一种干净的方式切换它们,保留接口和参数类型.
Common Lisp Interface Manager和多个后端
支持多个后端的CLOS中的UI层的示例是CLIM,Common Lisp Interface Manager.你可以研究它的软件设计.请参阅以下链接.例如,参见类似端口的协议(与显示服务的连接),介质(绘图发生的地方,对应于某种工作表的输出状态的协议类),工作表(用于绘制和输入的表面,大致类似于分层窗口),移植(一个代表主机窗口的工作表),...在应用程序中打开一个端口(例如到X11/Motif之类的特定窗口系统),应用程序的其余部分应该是运行基本不变.CLIM的体系结构将其所有服务映射到特定的CLIM后端,后端为X11/Motif(或您将使用的任何端口)提供接口.
例如,该功能draw-line将绘制到工作表,流和媒体.然后,通用函数 medium-draw-line*将实现各种版本的绘制线到一个或多个媒体子类.
总的来说,这不是很成功,因为便携式用户界面层带来了复杂性,需要大量的工作来开发和维护.在90年代中期,Lisp应用程序的市场很小(参见AI Winter),CLIM还不够好,而且实现是封闭源代码或专有代码.后来开发了一个名为McCLIM的开源/免费实现,它创建了工作软件 - 但最终开发者/用户失去了兴趣.
有点历史
在过去,Symbolics开发了一个名为"动态Windows"的用户界面系统.它于1986年发布.它运行在Symbolics操作系统中,可以绘制其原生OS /硬件组合和X11.从1988年左右开始,开发了基于便携式CLOS的版本.第一个可用的版本(特别是1991年的1.0版本)可以在几个平台上使用:Genera,X11,Mac和Windows.后来开发了一个新版本(版本2.0),它再次在各种系统上运行,但包含一个复杂的面向对象层,它提供了一个更明确的后端层,称为Silica.这个后端层不仅支持便携式绘图等内容,还支持抽象窗口系统的部分内容.更加雄心勃勃的部分,例如支持外观和感觉的适应(滑块,窗口样式,滚动条,菜单,对话框元素......)都没有完全解决,但至少可以作为第一代版本使用.
指针
二氧化硅:二氧化硅的实施反思(PDF)
规范(包括Silica):Common Lisp Interface Manager 2.0规范