Clojure Is Awesome!!! [PART 5]

(ns v2
(:require [clojure.spec.alpha :as s]
[clojure.string :as str]))

(s/def ::distance (s/and number? pos?))
(s/def ::package string?)
(s/def ::destination string?)
(s/def ::delivery-type #{“air” “land” “sea”})

(defprotocol DeliveryS…


This content originally appeared on DEV Community and was authored by André Borba

(ns v2
  (:require [clojure.spec.alpha :as s]
            [clojure.string :as str]))

(s/def ::distance (s/and number? pos?))
(s/def ::package string?)
(s/def ::destination string?)
(s/def ::delivery-type #{"air" "land" "sea"})

(defprotocol DeliveryService
  (calculate-cost [this distance] "Calculates the delivery cost based on the distance.")
  (process-delivery [this package destination] "Executes the delivery of the package to the destination.")
  (estimated-time [this distance] "Estimates delivery time in hours."))

(defrecord AirDelivery []
  DeliveryService
  (calculate-cost [_ distance]
    (* 5 distance))
  (process-delivery [_ package destination]
    (str "Package '" package "' will be delivered via Air to " destination))
  (estimated-time [_ distance]
    (Math/ceil (/ distance 800))))

(defrecord LandDelivery []
  DeliveryService
  (calculate-cost [_ distance]
    (* 2 distance))
  (process-delivery [_ package destination]
    (str "Package '" package "' will be delivered via Land to " destination))
  (estimated-time [_ distance]
    (Math/ceil (/ distance 60))))

(defrecord SeaDelivery []
  DeliveryService
  (calculate-cost [_ distance]
    (* 1 distance))
  (process-delivery [_ package destination]
    (str "Package '" package "' will be delivered via Sea to " destination))
  (estimated-time [_ distance]
    (Math/ceil (/ distance 30))))

(defmulti create-delivery-service
  "Factory multi-method for creating delivery services"
  (fn [type & _] (str/lower-case type)))

(defmethod create-delivery-service "air" [_]
  (->AirDelivery))

(defmethod create-delivery-service "land" [_]
  (->LandDelivery))

(defmethod create-delivery-service "sea" [_]
  (->SeaDelivery))

(defmethod create-delivery-service :default [type]
  (throw (ex-info "Invalid delivery type"
                  {:type type
                   :available-types #{"air" "land" "sea"}})))

(defn calculate-and-deliver
  "Service that uses the factory to calculate the cost and deliver a package.
   Returns a map with :cost, :delivery, and :estimated-time keys."
  [type package destination distance]
  {:pre [(s/valid? ::delivery-type type)
         (s/valid? ::package package)
         (s/valid? ::destination destination)
         (s/valid? ::distance distance)]}
  (try
    (let [service (create-delivery-service type)]
      {:cost (calculate-cost service distance)
       :delivery (process-delivery service package destination)
       :estimated-time (estimated-time service distance)})
    (catch Exception e
      (throw (ex-info "Delivery calculation failed"
                      {:cause (.getMessage e)
                       :type type
                       :package package
                       :destination destination
                       :distance distance})))))

(defn find-cheapest-delivery
  "Finds the cheapest delivery service for given parameters"
  [package destination distance]
  (->> ["air" "land" "sea"]
       (map #(-> [(calculate-and-deliver % package destination distance) %]))
       (sort-by (comp :cost first))
       first))

(comment
  (calculate-and-deliver "air" "Electronics" "São Paulo" 1000)
  ;; => {:cost 5000
  ;;     :delivery "Package 'Electronics' will be delivered via Air to São Paulo"
  ;;     :estimated-time 2}

  (find-cheapest-delivery "Heavy Machinery" "Porto Alegre" 800)
  ;; => [{:cost 800
  ;;      :delivery "Package 'Heavy Machinery' will be delivered via Sea to Porto Alegre"
  ;;      :estimated-time 27}
  ;;     "sea"]

  ;; Validation error example
  (calculate-and-deliver "air" "Books" "Curitiba" -100)
  ;; => Assertion Error: Invalid input
)


This content originally appeared on DEV Community and was authored by André Borba


Print Share Comment Cite Upload Translate Updates
APA

André Borba | Sciencx (2025-01-21T22:53:47+00:00) Clojure Is Awesome!!! [PART 5]. Retrieved from https://www.scien.cx/2025/01/21/clojure-is-awesome-part-5/

MLA
" » Clojure Is Awesome!!! [PART 5]." André Borba | Sciencx - Tuesday January 21, 2025, https://www.scien.cx/2025/01/21/clojure-is-awesome-part-5/
HARVARD
André Borba | Sciencx Tuesday January 21, 2025 » Clojure Is Awesome!!! [PART 5]., viewed ,<https://www.scien.cx/2025/01/21/clojure-is-awesome-part-5/>
VANCOUVER
André Borba | Sciencx - » Clojure Is Awesome!!! [PART 5]. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/01/21/clojure-is-awesome-part-5/
CHICAGO
" » Clojure Is Awesome!!! [PART 5]." André Borba | Sciencx - Accessed . https://www.scien.cx/2025/01/21/clojure-is-awesome-part-5/
IEEE
" » Clojure Is Awesome!!! [PART 5]." André Borba | Sciencx [Online]. Available: https://www.scien.cx/2025/01/21/clojure-is-awesome-part-5/. [Accessed: ]
rf:citation
» Clojure Is Awesome!!! [PART 5] | André Borba | Sciencx | https://www.scien.cx/2025/01/21/clojure-is-awesome-part-5/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.