对于一个项目,我正在创建一个类driver%,它应该是提供相同过程的不同模块的抽象层。该类将使用指定要使用的模块的参数进行初始化。
此外,我想driver%公开相同的过程但没有副作用,以方便使用驱动程序的单元测试类。
考虑以下:
module_one.rkt
#lang racket
(provide foo)
(define (foo)
(display "called from "module one"))
Run Code Online (Sandbox Code Playgroud)
module_two.rkt
#lang racket
(provide foo)
(define (foo)
(display "called from "module two"))
Run Code Online (Sandbox Code Playgroud)
driver.rkt
#lang racket
(require (prefix-in one: "module_one.rkt")
(prefix-in two: "module_two.rkt"))
(provide driver%)
(define driver%
(class object%
(super-new)
(init driver-choice)
(define choice driver-choice)
(define/public (foo)
(case choice
[(1) (one:foo)]
[(2) (two:foo)]
[else void]))))
Run Code Online (Sandbox Code Playgroud)
这满足了上述要求,但不是很优雅:对于每个公开的过程,必须添加另一个 case 表达式。这似乎没有必要,因为 API 的选择是在类实例化时做出的,所以选择在任何地方都是相同的。
对于这个问题,什么是更可接受的解决方案?我已经研究过使用local-require,但这似乎不起作用define/public。
非常感谢!
您可以使用dynamic-require动态要求模块。您还可以定义宏来减少重复代码。
但首先请注意,可以class完全避免:
;; module-one.rkt
#lang racket
(provide foo bar)
(define (foo) (displayln "called foo from module-one"))
(define (bar) (displayln "called bar from module-one"))
Run Code Online (Sandbox Code Playgroud)
;; module-two.rkt
#lang racket
(provide foo bar)
(define (foo) (displayln "called foo from module-two"))
(define (bar) (displayln "called bar from module-two"))
Run Code Online (Sandbox Code Playgroud)
;; driver.rkt
#lang racket
(define ((make-driver choice) method-name)
(case choice
[(1) ((dynamic-require "module-one.rkt" method-name))]
[(2) ((dynamic-require "module-two.rkt" method-name))]
[else (void)]))
(define a-driver (make-driver 1))
(a-driver 'foo)
(a-driver 'bar)
(define b-driver (make-driver 2))
(b-driver 'foo)
(b-driver 'bar)
Run Code Online (Sandbox Code Playgroud)
输出:
called foo from module-one
called bar from module-one
called foo from module-two
called bar from module-two
Run Code Online (Sandbox Code Playgroud)
如果您确实想使用class,这里有一种可能性:
;; driver.rkt
#lang racket
(require syntax/parse/define)
(define-simple-macro (driver
#:modules ([mod-id mod-path] ...)
#:methods (methods ...))
(class object% (super-new)
(init-field driver-choice)
(begin
(define/public (methods)
(define method-name 'methods)
(case driver-choice
[(mod-id) ((dynamic-require mod-path method-name))]
...
[else (void)])) ...)))
(define driver%
(driver
#:modules ([1 "module-one.rkt"] [2 "module-two.rkt"])
#:methods (foo bar)))
(define a-driver (new driver% [driver-choice 1]))
(send a-driver foo)
(send a-driver bar)
(define b-driver (new driver% [driver-choice 2]))
(send b-driver foo)
(send b-driver bar)
Run Code Online (Sandbox Code Playgroud)
输出:
called foo from module-one
called bar from module-one
called foo from module-two
called bar from module-two
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
214 次 |
| 最近记录: |