I think "design patterns" are unneccesarily geared towards "oo patterns" and completely avoiding much simpler ideas. What we're talking about here is a (simple) data pipeline.
I would try to do it in clojure. Any other language where functions are first-class is probably ok as well. Maybe I could a C# example later on, but it's not as nice. My way of solving this would be the following steps with some explanations for non-clojurians:
1. Represent a set of transformations.
(def transformations { :encrypt (fn [data] ... ) :compress (fn [data] ... )}) This is a map, i.e. a lookup table/dictionary/whatever, from keywords to functions. Another example (keywords to strings):
(def employees { :A1 "Alice" :X9 "Bob"}) (employees :A1) ; => "Alice" (:A1 employees) ; => "Alice" So, writing (transformations :encrypt) or (:encrypt transformations) would return the encrypt function. ((fn [data] ... ) is just a lambda function.)
2. Get the options as a sequence of keywords:
(defn do-processing [options data] ;function definition ...) (do-processing [:encrypt :compress] data) ;call to function 3. Filter all transformations using the supplied options.
(let [ transformations-to-run (map transformations options)] ... ) Example:
(map employees [:A1]) ; => ["Alice"] (map employees [:A1 :X9]) ; => ["Alice", "Bob"] 4. Combine functions into one:
(apply comp transformations-to-run) Example:
(comp f g h) ;=> f(g(h())) (apply comp [f g h]) ;=> f(g(h())) 5. And then together:
(def transformations { :encrypt (fn [data] ... ) :compress (fn [data] ... )}) (defn do-processing [options data] (let [transformations-to-run (map transformations options) selected-transformations (apply comp transformations-to-run)] (selected-transformations data))) (do-processing [:encrypt :compress]) The ONLY changes if we want to add a new function, say "debug-print", is the following:
(def transformations { :encrypt (fn [data] ... ) :compress (fn [data] ... ) :debug-print (fn [data] ...) }) ;<--- here to add as option (defn do-processing [options data] (let [transformations-to-run (map transformations options) selected-transformations (apply comp transformations-to-run)] (selected-transformations data))) (do-processing [:encrypt :compress :debug-print]) ;<-- here to use it (do-processing [:compress :debug-print]) ;or like this (do-processing [:encrypt]) ;or like this