如何在其中创建具有可更新公寓的可更新功能图?

时间:2011-02-20 03:13:55

标签: clojure

我有两个主要目标:

1。){:foo (fn ...)}应该在函数映射之外定义,允许你更新:foo's (fn ...)(也许是ref,但可能是一个原子)

2。)condp:"fred", "ethel"的案例应该存在于可以更新的结构中。例如,如果我想将"lucy" (handle-lucy a b c d)添加到condp中,我希望能够通过使用单独的结构来保存condp的所有情况。例如,将它们放在地图或矢量中意味着变量a b message and d在该结构的上下文中不可用。

摘要:帮助我重构这一点,使:foo:bar自己的函数存在于#'function-map中,可以在程序运行时更新。另外,帮我找到一种方法来获取condp的情况并将它们放入自己的可更新容器中。

总结2:如果你认为我所要求的是疯狂的,那就重新考虑一下你认为合适的事情吧​​。我主要对提高可读性和可访问性感兴趣。

这是我正在努力重构的功能图的缩短版本

(def function-map
  {:foo (fn [{:keys [a b message d]}]
          (let [[command & args] (.split message " ")]
            (condp = command
                "fred" (handle-fred a b @d)
                "ethel" (handle-ethel a b (first args) @d)
                nil)))
   :bar (fn [{:keys [a b c]}]
          (do-something a b c))})

1 个答案:

答案 0 :(得分:3)

1)这里明显的选择是使函数映射包含映射的ref / atom或使每个键的值成为包含函数的ref / atom。我不能从你的描述中判断哪个更有意义。 1 ref / atom更简单,但对function-map的任何更改都可能会为每个其他更改创建一个事务冲突。我猜这张地图不是经常变化而只是偶尔变化,在这种情况下1 ref / atom可能就足够了。原子用于不协调的同步变化。 Refs用于协调(事务)同步更改。如果您需要将多个函数一起更改为事务的一部分或执行比较和设置类型行为,请使用ref。否则,使用原子。

2)对于condp部分,听起来像你想要基于值的动态(多态)行为。要做到这一点,不要使用condp;使用具有利用可变状态的调度函数的多方法。这将允许您动态添加案例(defmethods)而无需修改调度代码。如果您想在事后“更新”命令集,请随时添加新的defmethod。如果要在处理时访问状态,只需将其传递给处理程序定义。

(defmulti handle-command (fn [command a b message d & args] command))
(defmethod handle-command "fred" [_ a b _ d] (handle-fred a b d))
(defmethod handle-command "ethel" [_ a b _ d [f & _]] (handle-ethel a b f d))

(def function-map
  {:foo (fn [{:keys [a b message d]}]
          (let [[command & args] (.split message " ")]
            (handle-command command a b message @d args)))})

对拼写错误道歉......实际上并没有在复制中尝试任何此类错误。