我正在编写这个程序,就像在线论坛的网络爬虫一样。对于我抓取的每个论坛,我都需要做同样的事情:
现在虽然每个论坛都需要同样的逻辑,但每个论坛的实施都是不同的。例如,每个登录表单的输入在每个论坛中是不同的。一个论坛可能有一个名为“username”的字段,另一个论坛可能有一个名为“user”的字段。其中一些步骤可能具有默认实现。例如,login
的默认实现是不做任何事情(因为您不必登录某些论坛来抓取它)。
我所做的是创建了一个函数,其中包含名为crawl-forum
的所有这些步骤,但这些实现是抽象的并在其他地方实现。我的问题是,让crawl-forum
使用这些实施的最佳方式是什么?
这是我到目前为止所尝试的内容。我在名为crawl-forum
的{{1}}函数中添加了一个新参数。这是一个如下所示的地图数据结构:
configs
调用{ :login login-function
:find-boards find-boards-function
...
}
的代码负责填充该地图。我不喜欢这个是crawl-forum
需要在整个configs
代码中传递。它随处可见新参数。另外,我有一些用于处理默认实现的蹩脚的临时代码。
我在irc上谈到了这一点,有人给了我一个想法,我应该使用多方法来代替,因为它确实是多态行为。它们看起来像这样:
crawl-forum
然后客户端代码必须在外部定义自己的多方法:
(defn get-site-key [& args] (first args))
(defmulti login get-site-key)
(defmethod login :default [site-key cookie-store] nil)
我不喜欢这个,就像(defmethod login :forum-1 [site-key cookie-store] (do-something cookie-store))
一样,我必须将config
传递给site-key
函数,crawl-forum
仍然有在里面到处传递。此外,每个site-key
必须作为参数传递给自己的defmethod
,但它们都不会永远使用它。这只是发送的必要论据。虽然我很难找到一个彻底的多方法教程,所以如果有更聪明的方法,请告诉我。
还有第三种选择更好吗?有没有更好的方法来使用多方法?让我知道,谢谢。
答案 0 :(得分:1)
您可以使用Protocols
。这些是支持多态行为的多方法的后继者。此外,在定义协议时,它可以使用:gen-class
命名空间指令编译到Java接口。
以下是一些有助于您理解的好链接:
但是,我偏爱一种简单的实现方法。维护论坛URL的地图以映射您的功能,即
(def config
{"http://forum1.com" {:login login-function1
:find-boards find-boards-function1 ... }
"http://forum2.com" {:login login-function2
:find-boards find-boards-function2 ... }
;; etc
"http://forumN.com" {:login login-functionN
:find-boards find-boards-functionN ... }})
和其他地方
(crawl-forum (get config forum-url))
我认为这种简单的方法在小型应用程序中没有任何问题。接口和多态性适用于大型项目,团队成员按距离和时间分开。
答案 1 :(得分:1)
我会选择选项1.如果传递地图困扰你,你总是可以使用动态变量。对于默认值,我建议使用merge:
(def defaults { ... })
(def site-specific (merge defaults { ...}))