多态性

    使用multimethod是一种快速在代码里面引入polymorphism的方法,我们可以定义一个dispatching function,然后指定一个dispatching value,通过它来确定调用哪一个函数。

    譬如,我们需要计算一个图形的面积,我们知道,如果是一个长方形,那么方法就是with * heigth,如果是圆形,那么就是 PI * radius * radius

    我们在repl里面执行:

    1. user=> (area r)
    2. 52
    3. user=> (area c)
    4. 452.3893421169302
    5. user=> (area {})
    6. :oops

    protocol其实更类似其他语言里面interface,我们定义一个protocol,然后用不同的类型去特化实现,我们以jepsen的代码为例,因为jepsen可以测试很多db,所以它定义了一个dbprotocol

    1. (setup! [db test node] "Set up the database on this particular node.")
    2. (teardown! [db test node] "Tear down the database on this particular node."))

    上面的代码定义了一个DBprotocol,然后有两个函数接口,用来setupteardown对应的db,所以我们只需要在自己的db上面实现这两个函数就能让jepsen调用了,伪代码如下:

    然后就能直接使用DB protocol了。

    1. user=> (setup! my-db :test :node)
    2. "hello db"
    3. user=> (teardown! my-db :test :node)
    4. "goodbye db"

    record的定义很简单,我们使用来定义:

    1. user=> (defrecord person [name age])
    2. user.person

    这里,我们定义了一个personrecord,它含有nameage两个字段,然后我们可以通过下面的方法来具体创建一个person:

    因为record其实可以认为是一个map,所以很多map的操作,我们也同样可以用于record上面。

    1. user=> (def siddon (->person "siddon" 30))
    2. user=> (assoc siddon :name "tang")
    3. #user.person{:name "tang", :age 30}
    4. user=> (dissoc siddon :name)
    5. {:age 30}
    1. (defprotocol SayP
    2. (say [this]))
    3. (defrecord person [name age]
    4. SayP
    5. (str "hello " name)))

    上面我们定义了SayP这个protocol,并且让这个record实现了相关的函数,然后我们就可以直接使用了。