简体   繁体   中英

How do I translate this Java example into idiomatic Clojure?

Most of the how do write Java example X in Clojure examples I've seen are neat snippets or algorithms. I'm wondering how to construct programs with Clojure. My working Java example is only 81 lines, but shows a User object which interacts with a MessageServer object. Additionally loads objects from a space-delimited text file. Also can imagine having to add more fields and methods on User.

How do I write this Java program in idiomatic Clojure?

// To run User.java, just do:
// % echo "iradik 555-5555" > users.txt &&  javac User.java && java User users.txt 555-5555
// Result should be:
// Messages for user iradik with phone 555-5555 are Hello!, Hello Again!

import java.io.*;
import java.util.*;

public class User {

    public static class PhoneNumberNotFoundException extends RuntimeException { }

    String      id;
    String      phoneNumber;
    String[]    messages;

    private static Map<String, User> PHONE_MAP = new HashMap<String, User>();

    public void getTextMessages() {
        if (messages == null || MessageServer.isChanged(this)) {
            MessageServer.getMessages(this);
        }
    }

    public void printTextMessages() {
         StringBuilder builder = new StringBuilder();
         if (messages.length > 0) {
             builder.append(messages[0]); 
         } 
         for (int i = 1; i < messages.length; ++i) {
             builder.append(", ");
             builder.append(messages[i]);
         }
         System.out.println("Messages for user " + id + " with phone " + phoneNumber + " is " + builder.toString());
    }

    public static User getUserForPhoneNumber(String phoneNumber) {
        User user = PHONE_MAP.get(phoneNumber);
        if (user == null) { throw new PhoneNumberNotFoundException(); }
        return user;
    }

    public static void initializeFromFile(String filename) throws IOException {
        FileInputStream fstream = new FileInputStream(filename);
        BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
        String strLine;
        while ((strLine = br.readLine()) != null)   {
            String[] d = strLine.split(" ");

            User user          = new User();
            user.id            = d[0];
            user.phoneNumber   = d[1];

            PHONE_MAP.put(user.phoneNumber, user);
       }
       in.close();
    }

    /** 
     * Run this:
     *   echo "steve 555-5555" > users.txt &&  javac User.java && java User users.txt 555-5555
     */
     public static void main(String[] args) throws IOException {
         User.initializeFromFile(args[0]);
         User user = User.getUserForPhoneNumber(args[1]);
         user.getTextMessages();
         user.printTextMessages();
     }
}

class MessageServer {
    static boolean isChanged(User user) {
        return true;
    }

    static void getMessages(User user) {
        user.messages = new String[] {"Hello!", "Hello Again!"};
    }
}

Here's some code snippets which hopefully is enough to get you started. I've put some users in the file resources/users.txt :

steve 555-5551234
bill 555-4441234
linus 555-3331234

You can experiment with the code via the repl instead of the command line

(ns textmsgs.core
  (:require [clojure.data.csv :as csv]
            [clojure.java.io :as io]))

(defrecord User [id phone])

(defn users-from-file
  "Reads a space delimited file of users"
  [filename]
  (with-open [r (io/reader filename)]
    (doall
      (map (partial apply ->User)
           (csv/read-csv r :separator \space)))))

(defn print-text-messages
  "Prints all the text messages for user"
  [user]
  (printf "Messages for %s with phone %s is %s"
          (:id user) (:phone user) (apply str (interpose \, (:messages user)))))

;; This is an in memory phone book
(def phone-db
  (agent (into {}
               (map #(vector (:phone %) %)
                    (users-from-file "resources/users.txt")))))

(defn text
  "Send a text message to a number"
  [number msg]
  (send phone-db
        (fn [db] 
          (if (contains? db number)
            (update-in db [number :messages] conj msg)
            (do (println "No such number" number)
                db)))))

;; Some things to try: 
;; (text "555-3331234" "Hey linus")
;; (print-text-messages (@phone-db "555-3331234"))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM