As I understand the problem in your example, you do have a definition
for what an Insurable is, but it's implicit: there's no way to check
whether an object is insurable and thus no way to check which parts of
the code break when the notion of being Insurable changes. Luckily
Clojure provides us with the tools needed to make the definition
explicit.

In your Java example you used an interface to define what an Insurable
is. In Clojure you can do the same with a protocol:

    (defprotocol Insurable
      (cost-to-replace-with-new [insurable]))

    (def insurable? (partial satisfies? Insurable))

Whenever you expect to receive an insurable, you can use a
precondition to make this assumption explicit, like BG and Meikel
suggested:

    (defn calculate-insurance [& insurables]
      {:pre [(every? insurable? insurables)]}
      ...)

Note that the Insurable objects are completely abstract; we don't know
or care what kind of data structure are used to implement them. This
means that we can't build valid Insurables by accident, like you did
in your example by calling FuncA to FuncE, but that's a *good* thing,
because data structures built like that are very brittle, as you
noted.

To wrap up the example, here are a two very different implementations
of Insurable. Note how everything is modeled in terms of domain
concepts instead of "maps with keys :x, :y and :z". We manipulate the
data structures with completely normal Clojure code, but keep the
knowledge of those data structures in one place only instead of
spreading it all over the codebase. This makes the code much more
robust and amenable to change.

    (defn make-simple-insurable [cost]
      {:post [(insurable? %)]}
      (reify Insurable
        (cost-to-replace-with-new [_]
          cost)))

    (defrecord CompositeInsurable [parts]
      Insurable
      (cost-to-replace-with-new [composite-insurable]
        (->> (:parts composite-insurable)
             (map cost-to-replace-with-new)
             (reduce +))))

    (defn make-composite-insurable [& parts]
      {:pre [(every? insurable? parts)]
       :post [(insurable? %)]}
      (CompositeInsurable. parts))

--
Timo

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to