Co rozumiem z rozmowy Stuart jest coś takiego:
(ns state.core)
(defn create-user-module [] (atom []))
(defn add-user [module user]
(swap! module conj user))
(defn get-users [module]
@module)
Teraz nie ma globalny stan w „core” jako funkcji, które manipulują stan spodziewać się go jako parametr. Umożliwia to łatwe testowanie, ponieważ można utworzyć nowe wystąpienie "modułu użytkownika" dla każdego testu. Ponadto klienci tego modułu nie powinni przejmować się tym, co otrzymują w funkcji create-user-module, powinni po prostu je przekazać bez sprawdzania go, w ten sposób można zmienić implementację modułu użytkownika w dowolnym momencie. Stuart mówi również o tworzeniu protokołów dla tych modułów, jeśli zamierzasz wdrożyć więcej niż jedną implementację.
Próbując odpowiedzieć na to pytanie, adapter pierścień jest tylko funkcją 1 param i compojure tylko biblioteki routingu, więc można utworzyć internetową aplikację za pomocą zamknięć, takich jak:
(ns state.web
(:use compojure.core)
(:require [state.core :as core]))
(defn web-module [user-module]
(routes
(GET "/all" [] (core/get-users user-module))))
teraz ty może wywołać moduł webowy w celu utworzenia aplikacji webapp, przekazując jako parametr wymagane zależności. Oczywiście trzeba jeszcze kogoś do tworzenia aplikacji internetowych z prawidłowymi użytkowników modułów, więc wystarczy do „main” funkcję przewody wszystko razem:
(ns state.main
(:require state.core
state.web)
(:use ring.adapter.jetty))
(defn start []
(let [user-module (state.core/create-user-module)
web-module (state.web/web-module user-module)]
(run-jetty web-module {:port 3000 :join? false})))
(defn stop [app]
(.stop app))
start
będzie wywoływana z metody app main
. Oznacza to tylko, że musisz przejść do wtyczki lein-run.
Teraz, biorąc pod uwagę, że pytasz o init
(z wtyczki Lein Ring, zakładam), myślę, że planujesz wdrożyć swoją aplikację webapp w pojemniku.Jako plugin pierścień Lein musi pracować w ramach ograniczeń Aplet java fw, a osoba zajmująca kończy się skompilowany do apletu java, najlepsze, co prawdopodobnie można zrobić coś takiego jak:
(ns state.web
(:use compojure.core)
(:require [state.core :as core]))
(def module-deps (atom {})
(defn init-app [] (swap! module-deps conj [:user-module (core/create-user-module)]))
(defroutes web-module []
(GET "/all" [] (core/get-users (:user-module @module-deps))))
to nadal oznacza, że rdzeń przestrzeń nazw jest łatwa do przetestowania, ale wciąż masz globalny stan w przestrzeni nazw, ale myślę, że jest "właściwie" obudowana i prawdopodobnie jest wystarczająco dobra, jeśli musisz użyć kontenera java.
A to tylko kolejny argument, dlaczego biblioteki są "lepsze" od frameworków :)
y! to dobre podejście. – hsestupin
@ hsestupin: Czy to jest pytanie LUB afirmacja :) – Ankur
Afirmacja ofc. Chodzi mi o to, że całkowicie zgadzam się z takim podejściem, kiedy nie można zmienić stanu przez bezpośrednie odniesienie. – hsestupin