In Clojure I want to have a protocol where some methods have a default implementation, and some have a custom one. And the first ones refer to the latter ones for configuration. Here is an example:
(defprotocol Saving
(save [this] "saves to mongodb")
(collection-name [this] "must return a string representing the associated MongoDB collection"))
;Default implementation
(extend-type Object
Saving
; the `save` method is common for all, so it is actually implemened here
(save [this] (mc/insert (collection-name [this]) this))
; this method is custom to every other type
(collection-name [this] "no_collection"))
;Particular implementations
(defrecord User
[login password]
Saving
(collection-name [this] "users"))
(defrecord NewsItem
[text date]
Saving
(collection-name [this] "news_items"))
However, it won't work this way. Even though calling collection-name
on a User
or NewsItem
instance returns a correct collection string, calling save
on them causes an AbstractMethodError
. How can I acheive this trivial OO-shaped goal with Clojure?
Make the save function a normal function:
(defn save [obj] (mc/insert (collection-name obj) obj))
The protocol should only have collection-name
(defprotocol Saving
(collection-name [this] "must return a string representing the associated MongoDB collection"))
And then each object that wants to be "saved" can implement this protocol.
Remember: OO style often hide the obvious simple thing :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With