[心得] 從0開始 3.真正的聊天室 (singleton)

看板mud (網路地下城/文字遊戲)作者 (虛空雷神獸)時間5年前 (2019/12/05 15:53), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串1/1
大家好! 歡迎收看從0開始的 MUD 開發第 3 集 在上一集我們已經實作了多執行緒的 telnet echo server 雖然我們的 server 可以支援複數使用者同時連線 但是使用者之間並沒有辦法互相溝通 所以這一集我們要講的是如何透過 java 內建的資料結構(HashMap)收集, 管理使用者 同時建立一個 PlayerManager, 藉由 PlayerManager 提供一個統一的操作介面 // PlayerManager.class // ✂--------------請沿虛線剪下-------------- package core; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; public class PlayerManager { // 宣告 static 的變數儲存 PlayerManager 的 instance // 這個寫法可以讓 PlayerManager 這個 class 被載入時, 立刻執行自己的建構子 private static PlayerManager instance = new PlayerManager(); // 用來儲存所有使用者的 Map private static Map<String, Player> players; // 重要! 一個 private 的建構子, 確保沒有其他程式可以 new PlayerManager() private PlayerManager() { players = new ConcurrentHashMap<>(); } // 一個 static 的 getInstance() 方法取代原有的建構子 // 原本常見的 PlayerManager pm = new PlayerManager(); // 寫法改為 PlayerManager pm = PlayerManager.getInstance(); public static PlayerManager getInstance() { return instance; } // 以下是真正提供給其他程式使用的方法 // 包括了新增、移除使用者的 addPlayer, removePlayer // 檢查使用者是否上線的 isPlayerOnline // 對所有使用者下指令的 forEach public void addPlayer(String name, Player player) { players.put(name, player); } public void removePlayer(String name) { players.remove(name); } public boolean isPlayerOnline(String name) { return players.containsKey(name); } public void forEach(BiConsumer<? super String, ? super Player> biConsumer) { players.forEach(biConsumer); } } // ✂--------------請沿虛線剪下-------------- 有了 PlayerManager 的支援, 原本的 Player.run() 功能也得到了進一步的擴充 // 在原有的 Player class 中新增一個 String playerName 儲存使用者的 ID private String playerName; public void run() { try { // 剛寫好的 PlayerManager 在這邊派上用場, 讓他來負責處理關於使用者的事務 PlayerManager pm = PlayerManager.getInstance(); write("歡迎來到 telnet chat server! (多執行緒版本)"); write("請問您的大名?"); // 一個簡易判斷線上是否有同名使用者的小程式 // 如果有同名使用者則一直執行無限迴圈, 直到使用者輸入了不衝突的新 ID String name; while (pm.isPlayerOnline(name = read())) { write("線上已經有一個叫做" + name + "的使用者了! 請重新輸入"); } // 當使用者輸入了獨一無二的 ID 後, 先對所有線上使用者廣播 // 再將目前的使用者加入 players playerName = name; pm.forEach((k, v) -> v.write(playerName + "上線囉")); pm.addPlayer(playerName, this); write(playerName + "你好! 歡迎進入聊天室"); while (true) { String input = read(); if ("quit".equalsIgnoreCase(input)) { socket.close(); // 別忘了使用者下線後必須把他移除 pm.removePlayer(playerName); pm.forEach((k, v) -> v.write(playerName + "離開了")); break; } // 原本只是呼叫個別使用者的 write() // 現在改為使用 forEach 呼叫所有使用者的 write() 達到 chat 的效果 pm.forEach((k, v) -> v.write("【閒聊】" + playerName + "說:" + input)); } } catch (IOException ignored) {} } 以下是三開連線的畫面 如何? MUD 的味道是不是開始慢慢出現了? XD https://i.imgur.com/9l27OV9.png
-- ╔═ ═╦╦═════╦═════╗ ◤◤◤ ╠╣飛鳥ももこ╠═╗ ║ ║╚═════╝ ╚═╦═╣ ║╔══════╗╔═╩═╣ █◤ ╠╣Momoko Asuka╠╝ ║ ◣◢◣◢╩╩══════╩════╝ -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 211.72.253.40 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/mud/M.1575532413.A.3C7.html
文章代碼(AID): #1TwBTzF7 (mud)
文章代碼(AID): #1TwBTzF7 (mud)