Skip to content

Instantly share code, notes, and snippets.

@david-mcneil
Created August 18, 2017 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save david-mcneil/f6574afd0b3e4260dd70d65455c09833 to your computer and use it in GitHub Desktop.
Save david-mcneil/f6574afd0b3e4260dd70d65455c09833 to your computer and use it in GitHub Desktop.
;; Define a "base type" of Dog
(defrecord Dog [breed])
;; Define a "sub type" of TrainedDog
(defrecord TrainedDog [dog word])
;; The interface that both Dog and TrainedDog will implement
(defprotocol Talker
(bark [_])
(speak
[_]
[_ s])
(to-dog [_]))
;; The base behavior that will be used for Dogs and TrainedDogs
(def base-behavior {:bark (fn [doggable]
(str "arf (" (:breed (to-dog doggable)) ")"))
:speak (fn
([doggable]
(bark doggable))
([doggable s]
(str (bark doggable) " " s)))
:to-dog (fn [dog] dog)})
;; Use the base behavior as the implmentation of the Dog Talker behavior.
(extend Dog
Talker
base-behavior)
(def fido (Dog. "collie"))
(bark fido)
;; => "arf (collie)"
(speak fido)
;; => "arf (collie)"
(speak fido "hi")
;; => "arf (collie) hi"
;; For the TrainedDog, start with the base-behavior but "override" two
;; of the functions with alternate behavior.
(extend TrainedDog
Talker
(merge base-behavior
{:speak (fn ([trained-dog]
(str (:word trained-dog)))
([trained-dog s]
(str (:word trained-dog) " " s)))
:to-dog (fn [trained-dog] (:dog trained-dog))}))
(def rex (TrainedDog. (Dog. "yorkie") "hello"))
;; TrainedDogs use the 'bark' implementation from the base-behavior
(bark rex)
;; => "arf (yorkie)"
;; TrainedDogs use their own 'speak' implementation
(speak rex)
;; => "hello"
(speak rex "hi")
;; => "hello hi"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment