니가 새기능 추가하거나 있는거 없애려면 변수  key->dispatcher-converter 와 변환함수와 디스패치 함수만 추가로 넣거나 빼주면 런타임에 아 무 이상없이 걍 계속 돌아감.

이거로 더이상의 향상은 불가능 하게 됨.


특징요약:

- go lang 개념의 병렬 프로그래밍으로 멀티코어를 이용할 수 있도록 오버 엔지니어링 (사용자 입력이 아주 존나 빠른 경우에만 의미 있음)

- 로직의 철저한 디커플링으로 향후 확장성을 오버 엔지니어링 (숙제낸 이가 변덕이 죽 끓듯 할 때만 의미 있음)

- 컴파일 한번 후 런타임에 기능을 추가 삭제 하도록 오버 엔지니어링 (런타임에 계속 바뀌면서 돌아가는 거 희희덕 거리면 보는 변태에게만 의미 있음)



(defn user-input [channel]

  (go-loop [[ch & more-ch] (seq "dafvn kjhv89df77234u4mbdfjhGYTDCG;rkgfv")]

    (when ch 

      (>! channel (int ch))

      (recur more-ch))))


(defn processor [converter in-channel out-channel]

  (go-loop []

    (->> (<! in-channel)

        converter

        (>! out-channel))

    (recur)))


(defn int->upper [int]

  (-> (char int)

      clojure.string/upper-case))


(defn dispatch-low-alpha-ch? [v]

  (<= (int \a) v (int \z)))


(defn int->lower [int]

  (-> (char int)

      clojure.string/lower-case))


(defn dispatch-upper-alpha-ch? [v]

  (<= (int \A) v (int \Z)))


(defn int->char [int]

  (char int))


(defn dispatch-else-ch? [v]

  true)


(defn int->inc-5 [int]

  (+ int 5))


(defn dispatch-int-ch? [v]

  (<= (int \0) v (int \9)))


(def key->dispatcher-converter

  {:int-ch {:dispatcher dispatch-int-ch? :converter int->inc-5}

   :low-alpha-ch {:dispatcher dispatch-low-alpha-ch? :converter int->upper}

   :upper-alpha-ch {:dispatcher dispatch-upper-alpha-ch? :converter int->lower}

   :default {:dispatcher dispatch-else-ch? :converter int->char}})


(defn distributor [in-ch channel-map]

  (go-loop []

    (let [val (<! in-ch)

          applicables (->> (filter (fn [[k m]]

                                     ((get m :dispatcher) val))

                                   key->dispatcher-converter)

                           (into {}))

          _ (assert (and (<= 1 (count applicables) 2)

                         (:default applicables))

              "Programming error!")

          [applicable] (-> (dissoc applicables :default)

                           keys)]

      (-> (or applicable :default)

           channel-map

           (>! val)))

    (recur)))


(defn make-distribution-channels [keys]

  (zipmap keys

          (repeatedly #(chan 1))))


(defn -main []

  (let [distribution-channel-map (-> (keys key->dispatcher-converter)

                                     make-distribution-channels)

        in-ch (chan 1)

        out-ch (chan 1)]

    (distributor in-ch distribution-channel-map)

    (doseq [[k ch] distribution-channel-map]

      (-> (get-in key->dispatcher-converter [k :converter])

          (processor ch out-ch)))

    (user-input in-ch)

    (go-loop [t (timeout 5000)]

      (let [[val chan] (alts! [t out-ch])]

        (if (= chan t)

          (flush)

          (do (print val)

              (recur t)))))))