2013-02-23 8 views
10

W Clojure chcę mieć protokół, w którym niektóre metody mają domyślną implementację, a niektóre mają niestandardową. A te pierwsze odnoszą się do tych ostatnich konfiguracji. Oto przykład:Clojure - domyślna implementacja protokołu mieszania z niestandardową implementacją

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

Jednak nie zadziała w ten sposób. Mimo że wywołanie collection-name w instancji User lub NewsItem zwraca prawidłowy ciąg kolekcji, wywołanie na nich save powoduje utworzenie AbstractMethodError. Jak mogę osiągnąć ten trywialny cel w kształcie OO z Clojure?

Odpowiedz

12

Wykorzystaj zapisać funkcjonować normalna funkcja:

(defn save [obj] (mc/insert (collection-name obj) obj)) 

Protokół powinien mieć tylko collection-name

(defprotocol Saving 
    (collection-name [this] "must return a string representing the associated MongoDB collection")) 

I wtedy każdy obiekt, który nie chce być „zbawieni” można wdrożyć ten protokół.

Pamiętaj: styl OO często ukrywają oczywistą rzeczą prostą :)

+0

Mam pytanie podobne do tego: Chcę abstrakcyjną metodę protokołu oraz zalegającego alias dla niego z identyczną funkcjonalność. Pseudonim mógłby po prostu wywołać metodę abstrakcyjną. Powodem użycia aliasu jest podanie przyjaznej dla użytkownika wywołującego Java. Czy mogę to osiągnąć? – Midiparse