clojure,如何减少重复代码(可能使用宏)

clojure, how to reduce repeated code (potentially using macro)

TL;DR

如何减少重复代码,例如从 job-inventory 创建两个作业/触发器,而不是重复两次并创建术语


;; deps in project.clj
;; [clojurewerkz/quartzite "2.1.0"]


(ns hello.scheduler
  (:require [clojurewerkz.quartzite.scheduler :as qs]
            [clojurewerkz.quartzite.triggers :as t]
            [clojurewerkz.quartzite.jobs :as j]
            [clojurewerkz.quartzite.jobs :refer [defjob]]
            [clojurewerkz.quartzite.schedule.cron :as cron])
  (:use clojure.tools.logging)
  (:gen-class))

(def job-inventory
  [{:name "add" :task '(+ 1 1) :cron "0/5 * * ? * *"}
   {:name "multiply" :task '(* 4 5)  :cron "0/3 * * ? * *"}])

(defjob add [ctx] (info "add called, return" (+ 1 1)))
(defjob multiply [ctx] (info "multiply called, return" (* 2 3)))

(defn auto
  []
  (let [s   (-> (qs/initialize) qs/start)
        _ (qs/clear! s)
        job (j/build
             (j/of-type add)
             (j/with-identity (j/key "job.add")))
        trigger (t/build
                 (t/with-identity (t/key "trigger.add"))
                 (t/start-now)
                 (t/with-schedule (cron/schedule
                                   (cron/cron-schedule "0/5 * * ? * *"))))
        _ (qs/schedule s job trigger)
        
        job (j/build
             (j/of-type multiply)
             (j/with-identity (j/key "job.multiply")))
        trigger (t/build
                 (t/with-identity (t/key "trigger.multiply"))
                 (t/start-now)
                 (t/with-schedule (cron/schedule
                                   (cron/cron-schedule "0/3 * * ? * *"))))
        _ (qs/schedule s job trigger)
        ]
    ))


类似于 http://clojurequartz.info/articles/getting_started.html 中描述的内容, 我有代码块来创建作业并挂钩它们以执行

问题是,当我得到越来越多的它们时,我想知道我是否可以有更好的方法来管理它们,比如从 job-inventory 创建/生成,而不是像 addmultiply

所以,要求再循环一层 有没有办法利用函数编程,避免创建新名称(在传统语言中说 python qt,如果我有一组按钮,我可以直接粉碎成一个巨大的字典,然后循环创建/禁用,相反,实际上将每个名称创建为顶级变量 )

我试过宏但是它说无法解决class添加,所以我猜我用错了

要记住的关键是函数是数据。虽然你不能很容易地动态创建 types(与通过 reify 实现接口的实例相反),但你可以静态创建一个 class 然后代理您的功能。

首先让我们将 job-inventory:task 设为一个函数。

(def job-inventory
  [{:name "add" :task (fn [] (println (+ 1 1))) :cron "0/5 * * ? * *"}
   {:name "multiply" :task (fn [] (println (* 4 5)))  :cron "0/3 * * ? * *"}])

然后我们需要代理工作class。这将执行它在作业数据中找到的函数。

;; require clojurewerkz.quartzite.conversion :as qc
(defjob proxy-job [ctx]
  (let [ctx (qc/from-job-data ctx)]
    ((ctx "proxied-fn"))))

然后我们创建一个调度函数,它从作业清单中获取一个映射并使用代理作业间接调度它。

(defn schedule [scheduler {:keys [:name :task :cron]}]
  (let [job (j/build
             (j/of-type proxy-job)
             (j/using-job-data {"proxied-fn" task})
             (j/with-identity (j/key (str "job." name))))
        trigger (t/build
                 (t/with-identity (t/key (str "trigger." name)))
                 (t/start-now)
                 (t/with-schedule (cron/schedule
                                   (cron/cron-schedule "0/3 * * ? * *"))))]
  (qs/schedule scheduler job trigger)
  scheduler)

(reduce scheduler schedule job-inventory)

如果 quartz 决定 serialise/deserialise 作业数据,这种方法可能会失败。我用另一层间接来解决这个问题,作为感兴趣的人的简单练习 reader - 老实说,我最初的想法是我们创建命名函数,然后我们通过符号引用它,但它使代理复杂化并使你想知道为什么不直接使用 defjob。如果您准备取消您的职能,您仍然可以在工作清单中参考它们并拥有基于数据的工作构建器功能。