3

我正在编写这个程序,它就像在线论坛的网络爬虫。对于我抓取的每个论坛,我都需要做同样的事情:

  1. 登录
  2. 找到板子
  3. 找到帖子
  4. 找到帖子的永久链接
  5. 查找发帖人的用户名
  6. 等等

现在,虽然每个论坛都需要发生相同的逻辑,但每个论坛的实现是不同的。例如,每个论坛的每个登录表单的输入都不同。一个论坛可能有一个名为“用户名”的字段,另一个可能有一个名为“用户”的字段。其中一些步骤可能具有默认实现。例如,默认实现login是不做任何事情(因为您不必登录某些论坛来抓取它)。

我所做的是创建了一个函数,其中包含所有这些步骤,crawl-forum但实现是抽象的并在其他地方实现。我的问题是,使用这些实现的最佳方式是什么?crawl-forum

我试过的

1) 配置图

这是我到目前为止所尝试的。我向crawl-forum名为configs. 这是一个如下所示的地图数据结构:

{ :login login-function
  :find-boards find-boards-function
  ...
}

调用的代码crawl-forum负责填充该映射。我不喜欢的是configs需要在整个crawl-forum代码中传递。它到处添加一个新参数。此外,我还有一些用于处理默认实现的蹩脚的临时代码。

2) 多方法

我在 irc 上谈到了这一点,有人给了我一个想法,我应该为此使用多方法,因为它确实是多态行为。它们看起来像这样:

(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-keyin 传递给crawl-forum函数,并且site-key仍然必须在内部到处传递。此外,每个defmethod人都必须将自己site-key的参数作为参数传回,但他们都不会使用它。这只是进行调度的必要参数。不过,我真的很难找到一个完整的多方法教程,所以如果有更聪明的方法可以做到这一点,请告诉我。

有没有更好的第三种选择?有没有更好的方法来使用多方法?让我知道,谢谢。

4

2 回答 2

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))

我认为这种简单的方法在小型应用程序中没有任何问题。接口和多态性适用于团队成员按距离和时间分开的大型项目。

于 2013-05-22T19:44:16.763 回答
1

我会选择选项 1。如果传递地图打扰您,您始终可以使用动态 var。对于默认值,我建议使用合并:

(def defaults { ... })
(def site-specific (merge defaults { ...}))
于 2013-05-22T22:26:42.830 回答