Aquí es un ejemplo simplista de la ilustración:Clojure permite la encapsulación y la herencia, pero ¿puedo combinarlas?
puedo encapsular un detalle de implementación, tales como el uso de un átomo de un contador:
(defn make-counter
([] (make-counter 0))
([init-val]
(let [c (atom init-val)]
{:get (fn [] @c)
:++ (fn [] (swap! c inc))})))
Pero eso significa que necesito para redefinir todo para añadir una característica (sin herencia):
(defn make-bi-counter
([] (make-bi-counter 0))
([init-val]
(let [c (atom init-val)]
{:get (fn [] @c)
:++ (fn [] (swap! c inc))
:-- (fn [] (swap! c dec))})))
Mientras que si fuera posible simplemente extender la función:
(assoc c :-- (env (:++ c) (fn [] (swap! c dec))))
(def c (make-counter))
(def b (make-bi-counter))
user=> ((:-- b))
-1
user=> ((:-- b))
-2
user=> ((:get b))
-2
O Me podría haber expuesto el átomo y tenía funciones independientes:
(defn -- [a] (swap! a dec))
(def a (atom 0))
(-- a)
Parece ser la mejor opción es renunciar a la encapsulación, si 'herencia' (o quizás más exactamente: la extensión) es deseable.
Creo que la encapsulación no se trata de "esconder cosas de uno mismo". Se trata de comunicar su diseño a otros antes que nada. – Alexey