View Category
OOP

Define a class

Declare a class named Greeter that takes a string on creation and greets using this string if you call the "greet" method.
clojure
(defprotocol IGreeter
(greet [this]))

(deftype Greeter [whom]
IGreeter
(greet [this]
(println (str "Hello, " whom))))

(greet (Greeter. "world"))
(defn greeter [whom]
{:whom whom})

(defn greet [g]
(println (str "Hello, " (:whom g))))

(greet (greeter "world"))

Instantiate object with mutable state

Reimplement the Greeter class so that the 'whom' property or data member remains private but is mutable, and is provided with getter and setter methods. Invoke the setter to change the greetee, invoke 'greet', then use the getter in displaying the line, "I have just greeted {whom}.".

For example, if the greetee is changed to 'Tommy' using the setter, the 'greet' method would display:

Hello, Tommy!

The getter would then be used to display the line:

I have just greeted Tommy.
clojure
(defn greeter [whom]
(atom {:whom whom}))

(defn get-whom [g]
(:whom @g))

(defn set-whom [g whom]
(swap! g #(conj % {:whom whom})))

(defn greet [g]
(println (str "Hello, " (:whom @g) "!")))

; using the "class"
(let [g (greeter "world")]
(greet g)
(set-whom g "Tommy")
(greet g)
(println (str "I have just greeted " (get-whom g) ".")))

; or same effect without using any variables
(println (str "I have just greeted "
(get-whom (doto (greeter "world")
(greet)
(set-whom "Tommy")
(greet)))
"."))

Implement Inheritance Heirarchy

Implement a Shape abstract class which will form the base of an inheritance hierarchy that models 2D geometric shapes. It will have:

* A non-mutable 'name' property or data member set by derived or descendant classes at construction time
* A 'area' method intended to be overridden by derived or descendant classes ( double precision floating point return value)
* A 'print' method (also for overriding) will display the shape's name, area, and all shape-specific values

Two derived or descendant classes will be created:
* Circle    -> Constructor requires a '
radius' argument, and a 'circumference' method to be implemented  
* Rectangle -> Constructor requires '
length' and 'breadth' arguments, and a 'perimeter' method to be implemented 

Instantiate an object of each class, and invoke each objects '
print' method to show relevant details.
clojure
(defmulti area :Shape)
(defmulti print :Shape)

; Circle methods
(defn circle [r]
{:Shape :Circle
:name "Circle"
:radius r})

(defn circumference [c]
(* 2 Math/PI (:radius c)))

(defmethod area :Circle [c]
(* Math/PI (:radius c) (:radius c)))

(defmethod print :Circle [c]
(println (format "I am a %s with ->" (:name c)))
(println (format "Radius: %.2f" (:radius c)))
(println (format "Area: %.2f" (area c)))
(println (format "Circumference: %.2f" (circumference c))))

; Rectangle methods
(defn rectangle [l b]
{:Shape :Rectangle
:name "Rectangle"
:length l
:breadth b})

(defn perimeter [r]
(+ (* 2 (:length r)) (* 2 (:breadth r))))

(defmethod area :Rectangle [r]
(* (:length r) (:breadth r)))

(defmethod print :Rectangle [r]
(println (format "I am a %s with ->" (:name r)))
(println (format "Length, Width: %.2f, %.2f" (:length r) (:breadth r)))
(println (format "Area: %.2f" (area r)))
(println (format "Perimeter: %.2f" (perimeter r))))

; usage of the "classes"
(let [shapes (list (circle 4.2) (rectangle 2.7 3.1) (rectangle 6.2 2.6) (circle 17.3))]
(doseq [shape shapes]
(print shape)))

Implement and use an Interface

Create a Serializable interface consisting of 'save' and 'restore' methods, each of which:

* Accept a stream or handle or descriptor argument for the source or destination
* Save to destination or restore from source the properties or data members of the implementing class (restrict yourself to the primitive types 'int' and 'string')

Next, create a Person class which has 'name' and 'age' properties or data members and implements this interface. Instantiate a Person object, save it to a serial stream, and instantiate a new Person object by restoring it from the serial stream.
clojure
(defn person [name age]
{:name name :age age})

(defn show [p]
(println (format "Name=%s Age=%d" (:name p) (:age p))))

(defn save [p filename]
(with-out-writer filename (pr p)))

(defn restore [filename]
(read (PushbackReader. (reader filename))))

(let [p (person "Ken" 38)]
(show p)
(save p *person-fn*))

(let [ser-p (restore *person-fn*)]
(show ser-p))