Skip to main content
3 of 3
added 104 characters in body
NiklasJ
  • 675
  • 4
  • 6

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 
NiklasJ
  • 675
  • 4
  • 6