On 29 July 2015 at 01:07, zcaudate <z...@caudate.me> wrote:

> The example in the article is probably the smallest example I can come up
> with.
>
> http://z.caudate.me/the-abstract-container-pattern
>
> The code for the concrete implementations speaks for itself I think, it is
> about 10 lines to hook in jetty and http-kit to the framework.
>

I'm afraid I don't see the benefit of having two tiers of abstraction in
your example. I think you could achieve the same result with a simpler
architecture.

For example, consider a protocol:

  (defprotocol Lifecycle
    (-start [service])
    (-stop [service]))

We can add additional functionality around this simply by wrapping the
protocol methods with functions:

  (defn start [service]
    (if (:started? service)
      service
      (-> service -start (assoc :started? true))))

  (defn stop [service]
    (if-not (:started? service)
      service
      (-> service -stop (dissoc :started?))))

So in this case we're adding idempotence and a key to determine whether or
not the service has been started. We assume that a service is a record that
implements Lifecycle.

We could also conceive of a function that globally registers services for
convenience:

  (def running-services (atom #{}))

  (defn register! [service]
    (swap! running-services conj service))

  (defn deregister! [service]
    (swap! running-services disj service))

Then work that into the start and stop functions:

  (defn start [service]
    (if (:started? service)
      service
      (-> service -start (assoc :started? true) (doto register!))))

  (defn stop [service]
    (if-not (:started? service)
      service
      (-> service (doto deregister!) -stop (dissoc :started?))))

Now, if we actually want to create a service for an adapter like Jetty:

  (defrecord JettyService [handler options]
    Lifecycle
    (-start [service]
      (assoc service :instance (run-jetty handler (assoc options :join?
false)))
    (-stop [service]
      (.stop (:instance service))
      (dissoc service :instance)))

Unless I've missed something, that seems like broadly equivalent
functionality, but with arguably less complexity. We stick with functions
for the most part, and only use polymorphism where it's necessary.

- James

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to