【发布时间】:2017-01-27 20:55:09
【问题描述】:
虽然下面的例子看起来有点奇怪,但这是因为我试图将我目前遇到的一个相当大的问题简化为一个最小的例子。当它们位于几个抽象层后面并且 defmulti 和相应的 defmethods 在多个命名空间中定义时,我正在努力解决如何调用多方法。我真的觉得我在这里遗漏了一些明显的东西......
假设我有以下场景:
- 我通过他们自己的专有接口从各种供应商那里购买东西
- 我想实现一个通用接口来与每个供应商对话
- 我希望能够从不同的供应商处购买不同的商品
使用 Clojure,实现通用接口的推荐方法是通过协议或多方法。在这种情况下,由于我根据供应商的价值进行切换,我认为处理我在下面描述的情况的最佳方法是通过多种方法(但我可能是错的)。
我的多方法定义看起来像这样,它定义了一个我想用来与每个供应商的 API 对话的通用接口:
(ns myapp.suppliers.interface)
(defmulti purchase-item :supplier)
(defmulti get-item-price :supplier)
对于每个供应商,我可能想要这样的东西:
(ns myapp.suppliers.supplier1
(:require [myapp.suppliers.interface :as supplier-api]))
(defmethod purchase-item :supplier1 [item quantity] ...)
(defmethod get-item-price :supplier1 [item] ...)
和
(ns myapp.suppliers.supplier2
(:require [myapp.suppliers.interface :as supplier-api]))
(defmethod purchase-item :supplier2 [item quantity] ...)
(defmethod get-item-price :supplier2 [item] ...)
到目前为止,没问题
现在我的代码调用这些抽象方法,我假设它看起来像:
(ns myapp.suppliers.api
(:require [myapp.suppliers.supplier1 :as supplier1]
[myapp.suppliers.supplier2 :as supplier2])
(defn buy-something
[supplier item quantity]
(purchase-item [supplier item quantity])
(defn price-something
[supplier item]
(get-item-price [supplier item])
这开始看起来有点……难看。每次实现新供应商的 API 时,我都需要将 myapp.suppliers.api 更改为 :require 新供应商的方法并重新编译。
现在我在下一个级别工作,我想从供应商 2 那里购买一个小部件。
(ns myapp.core
(:require [myapp.suppliers.api :as supplier])
(def buy-widget-from-supplier2
(buy-something :supplier2 widget 1)
这行不通,因为 :supplier2 尚未在此命名空间中的任何位置定义。
有没有更优雅的方式来编写这段代码?特别是在 myapp.core 中,我如何从 :supplier2 购买东西?
【问题讨论】:
-
“:supplier2 尚未在此命名空间中的任何位置定义”是什么意思?无需“定义”关键字。它只是一个随处可访问的文字(如 1 或“abc”)。
-
@OlegTheCat 我知道这是一个很难写下来的问题......我想做的是从 myapp.core 调用 (buy-something :supplier2 widget 1),但我认为我缺少一个引入所有依赖命名空间的好方法
标签: clojure protocols abstraction multimethod