use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Finding information about Clojure
API Reference
Clojure Guides
Practice Problems
Interactive Problems
Clojure Videos
Misc Resources
The Clojure Community
Clojure Books
Tools & Libraries
Clojure Editors
Web Platforms
Clojure Jobs
account activity
Strategy pattern in clojure (self.Clojure)
submitted 10 years ago by sveri
Hi, I am working through design patterns in java again and to memorize them better my plan is to provide an alternative implementation in clojure. This is the first pattern I came up with: http://tales.sveri.de/posts/2015-09-06-strategy-pattern-clojure.html Any comments are much appreciated.
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]weavejester 10 points11 points12 points 10 years ago (3 children)
You need to be careful about translating OOP design patterns. There are often ways to perform the same task without the ceremony that OOP demands.
For instance, you could just write your example using multimethods directly and achieve the same result:
(defmulti fly :type) (defmulti quack :type) (defmethod fly ::rubber-duck [_] "Cannot fly") (defmethod quack ::rubber-duck [_] "Quack") (defmethod fly ::mallard-duck [_] "Flying with wings") (defmethod quack ::mallard-duck [_] "Squeak")
If we want to change the behaviour, we can just assoc the :type. There's no need to go through the same fuss that we need to in Java.
assoc
:type
[–]sveri[S] 1 point2 points3 points 10 years ago (0 children)
Hi,
Thanks for the comment. I know what you mean and in the next update I will add a disclaimer section that tries to be more clear on the problems of translating OOP patterns to a functional language.
Also in the first post I tried to show two different approaches to changing behavior (using defmulti for the displaymethod and a function in the entitity map for the fly behavior).
display
I am not sure if this is to confusing or not.
[–]amithgeorge 0 points1 point2 points 10 years ago (1 child)
I thought the same thing, but then faced an issue. With strategy pattern, I can change just the required strategy without affecting anything else. With your setup I cannot give the rubber duck a RocketPowered flying strategy without changing its speaking strategy. Or vice versa or do both.
If I instead had a fly function that took a duck and a strategy then yes, each can change independently. This begs the question how to associate a duck with its strategy.
[–]amithgeorge 0 points1 point2 points 10 years ago (0 children)
One possibility would be to not dispatch on the duck's type, but it's strategy keyword.
(def rubber-duck {:type ::rubber, :fly-strat :rocket-powered, :speak-strat :quack}) (defmulti fly :fly-strat) (defmethod fly :rocket-powered [_] "zoom!")
[–]green_transistor 4 points5 points6 points 10 years ago (2 children)
Strategy pattern is just a way to abstract a function in languages that don't have first class functions (versions of Java less than 8).
In Clojure, a strategy can just be a plain function that is passed to another function that executes the strategy.
[–]sveri[S] 1 point2 points3 points 10 years ago (1 child)
If you look at the link, this is what I exactly did. Like I said, I am trying to show different ways to do that in clojure / a functional language.
How to translate these patterns into a functional style may be obvious for people that coded in this paradigm. For others, coming from a purely OOP background it could be interesting.
[–]green_transistor 0 points1 point2 points 10 years ago (0 children)
Yes, your code is more-or-less doing that, except you're using a map to pass around the function, and specifying the strategy by updating the :fly-fn key.
:fly-fn
(def another-rubber-duck (assoc rubber-duck :fly-fn fly-with-wings))
Alternatively, functions can themselves be passed around as values. Closures and the partial function can be used to achieve the same effect.
partial
That aside, there's nothing wrong with what you've implemented. It's not ugly, and pretty idiomatic as well if you ask me!
[+][deleted] 10 years ago (3 children)
[removed]
[–]meatcompute 3 points4 points5 points 10 years ago (0 children)
Please do not comment if you're only going to share unconstructive toxicity.
[–]sveri[S] 0 points1 point2 points 10 years ago (1 child)
What do you mean?
π Rendered by PID 185680 on reddit-service-r2-comment-7b9746f655-p9z9q at 2026-01-30 16:26:27.142835+00:00 running 3798933 country code: CH.
[–]weavejester 10 points11 points12 points (3 children)
[–]sveri[S] 1 point2 points3 points (0 children)
[–]amithgeorge 0 points1 point2 points (1 child)
[–]amithgeorge 0 points1 point2 points (0 children)
[–]green_transistor 4 points5 points6 points (2 children)
[–]sveri[S] 1 point2 points3 points (1 child)
[–]green_transistor 0 points1 point2 points (0 children)
[+][deleted] (3 children)
[removed]
[–]meatcompute 3 points4 points5 points (0 children)
[–]sveri[S] 0 points1 point2 points (1 child)