做者:小傅哥
博客:https://bugstack.cnhtml
沉澱、分享、成長,讓本身和他人都能有所收穫!😄
老闆你加錢個人代碼能飛
java
程序員這份工做裏有兩種人;一類是熱愛喜歡的、一類是僅當成工做的。而喜歡代碼編程的這部分人會極其主動學習去豐富本身的羽翼,也很是喜歡對技術探索力求將學到的知識賦能到平時的業務需求開發中。對於這部分小夥伴來講上班寫代碼還能賺錢真的是幸福!程序員
怎麼成爲喜歡編碼都那部分人
面試
不管作哪行那業你都喜歡,每每來自從中持續不斷都獲取成就感。就開發編程而言由於你的一行代碼影響到了千千萬萬的人、由於你的一行代碼整個系統更加穩定、由於你的一行代碼扛過了全部秒殺等等,這樣一行行的代碼都是你日積月累學習到的經驗。那若是你也想成爲這樣有成就感的程序員就須要不斷的學習,不斷的用更多的技能知識把本身編寫的代碼運用到更核心的系統。編程
方向不對努力白費
設計模式
日常你也付出了不少的時間,但就是沒有獲得多少收益。就像有時候不少小夥伴問我,我是該怎麼學一個我沒接觸過的內容。個人我的經驗很是建議,先不要學太多理論性的內容,而是嘗試實際操做下,把要學的內容作一些Demo案例出來。這有點像你買了個自行車是先拆了學學怎麼個原理,仍是先騎幾圈呢?哪怕摔了跟頭,但那都是必須經歷後留下的經驗。架構
一樣我也知道不少人看了設計模式收穫不大,這主要新人對沒有案例或者案例不貼近實際場景沒有學習方向致使。太空、太虛、太玄,讓人沒有抓手!app
因此我開始編寫以實際案例爲着手的方式,講解設計模式的文章,幫助你們成長的同時也讓我本身有所沉澱!dom
bugstack蟲洞棧
,回覆源碼下載
獲取(打開獲取的連接,找到序號18)工程 | 描述 |
---|---|
itstack-demo-design-4-00 | 場景模擬工程,模擬在線考試題庫抽提打亂順序 |
itstack-demo-design-4-01 | 使用一坨代碼實現業務需求,也是對ifelse的使用 |
itstack-demo-design-4-02 | 經過設計模式優化改造代碼,產生對比性從而學習 |
原型模式主要解決的問題就是建立重複對象,而這部分對象
內容自己比較複雜,生成過程可能從庫或者RPC接口中獲取數據的耗時較長,所以採用克隆的方式節省時間。ide
其實這種場景常常出如今咱們的身邊,只不過不多用到本身的開發中,就像;
Ctrl+C
、Ctrl+V
,複製粘貼代碼。Object clone()
。相似以上的場景並很多,但若是讓你去思考平時的代碼開發中,有用到這樣的設計模式嗎?確實不那麼容易找到,甚至有時候是忽略了這個設計模式的方式。在沒有閱讀下文以前,也能夠思考下哪些場景能夠用到。
每一個人都經歷過考試,從紙製版到上機答題,大大小小也有幾百場。而之前坐在教室裏答題身邊的人都是一套試卷,考試的時候還能偷摸或者別人給發信息抄一抄答案。
但從一部分能夠上機考試的內容開始,在保證你們的公平性同樣的題目下,開始出現試題混排更有作的好的答案選項也混排。這樣大大的增長了抄的成本,也更好的作到了考試的公平性。
但若是這個公平性的考試需求交給你來完成,你會怎麼作?
由於須要實現一個上機考試抽題的服務,所以在這裏建造一個題庫題目的場景類信息,用於建立;選擇題
、問答題
。
itstack-demo-design-4-00 └── src └── main └── java └── org.itstack.demo.design ├── AnswerQuestion.java └── ChoiceQuestion.java
ChoiceQuestion
(選擇題)、AnswerQuestion
(問答題)。若是是實際的業務場景開發中,會有更多的題目類型,能夠回憶一下你的高考試卷。public class ChoiceQuestion { private String name; // 題目 private Map<String, String> option; // 選項;A、B、C、D private String key; // 答案;B public ChoiceQuestion() { } public ChoiceQuestion(String name, Map<String, String> option, String key) { this.name = name; this.option = option; this.key = key; } // ...get/set }
public class AnswerQuestion { private String name; // 問題 private String key; // 答案 public AnswerQuestion() { } public AnswerQuestion(String name, String key) { this.name = name; this.key = key; } // ...get/set }
今天的實現方式沒有ifelse了,可是沒有一個類解決不了的業務,只要你膽大!
在如下的例子中咱們會按照每個用戶建立試卷的題目,並返回給調用方。
itstack-demo-design-4-01 └── src └── main └── java └── org.itstack.demo.design └── QuestionBankController.java
public class QuestionBankController { public String createPaper(String candidate, String number) { List<ChoiceQuestion> choiceQuestionList = new ArrayList<ChoiceQuestion>(); List<AnswerQuestion> answerQuestionList = new ArrayList<AnswerQuestion>(); Map<String, String> map01 = new HashMap<String, String>(); map01.put("A", "JAVA2 EE"); map01.put("B", "JAVA2 Card"); map01.put("C", "JAVA2 ME"); map01.put("D", "JAVA2 HE"); map01.put("E", "JAVA2 SE"); Map<String, String> map02 = new HashMap<String, String>(); map02.put("A", "JAVA程序的main方法必須寫在類裏面"); map02.put("B", "JAVA程序中能夠有多個main方法"); map02.put("C", "JAVA程序中類名必須與文件名同樣"); map02.put("D", "JAVA程序的main方法中若是隻有一條語句,能夠不用{}(大括號)括起來"); Map<String, String> map03 = new HashMap<String, String>(); map03.put("A", "變量由字母、下劃線、數字、$符號隨意組成;"); map03.put("B", "變量不能以數字做爲開頭;"); map03.put("C", "A和a在java中是同一個變量;"); map03.put("D", "不一樣類型的變量,能夠起相同的名字;"); Map<String, String> map04 = new HashMap<String, String>(); map04.put("A", "STRING"); map04.put("B", "x3x;"); map04.put("C", "void"); map04.put("D", "de$f"); Map<String, String> map05 = new HashMap<String, String>(); map05.put("A", "31"); map05.put("B", "0"); map05.put("C", "1"); map05.put("D", "2"); choiceQuestionList.add(new ChoiceQuestion("JAVA所定義的版本中不包括", map01, "D")); choiceQuestionList.add(new ChoiceQuestion("下列說法正確的是", map02, "A")); choiceQuestionList.add(new ChoiceQuestion("變量命名規範說法正確的是", map03, "B")); choiceQuestionList.add(new ChoiceQuestion("如下()不是合法的標識符", map04, "C")); choiceQuestionList.add(new ChoiceQuestion("表達式(11+3*8)/4%3的值是", map05, "D")); answerQuestionList.add(new AnswerQuestion("小紅馬和小黑馬生的小馬幾條腿", "4條腿")); answerQuestionList.add(new AnswerQuestion("鐵棒打頭疼仍是木棒打頭疼", "頭最疼")); answerQuestionList.add(new AnswerQuestion("什麼牀不能睡覺", "牙牀")); answerQuestionList.add(new AnswerQuestion("爲何好馬不吃回頭草", "後面的草沒了")); // 輸出結果 StringBuilder detail = new StringBuilder("考生:" + candidate + "\r\n" + "考號:" + number + "\r\n" + "--------------------------------------------\r\n" + "1、選擇題" + "\r\n\n"); for (int idx = 0; idx < choiceQuestionList.size(); idx++) { detail.append("第").append(idx + 1).append("題:").append(choiceQuestionList.get(idx).getName()).append("\r\n"); Map<String, String> option = choiceQuestionList.get(idx).getOption(); for (String key : option.keySet()) { detail.append(key).append(":").append(option.get(key)).append("\r\n"); ; } detail.append("答案:").append(choiceQuestionList.get(idx).getKey()).append("\r\n\n"); } detail.append("2、問答題" + "\r\n\n"); for (int idx = 0; idx < answerQuestionList.size(); idx++) { detail.append("第").append(idx + 1).append("題:").append(answerQuestionList.get(idx).getName()).append("\r\n"); detail.append("答案:").append(answerQuestionList.get(idx).getKey()).append("\r\n\n"); } return detail.toString(); } }
接下來咱們經過junit單元測試的方式驗證接口服務,強調平常編寫好單測能夠更好的提升系統的健壯度。
編寫測試類:
@Test public void test_QuestionBankController() { QuestionBankController questionBankController = new QuestionBankController(); System.out.println(questionBankController.createPaper("花花", "1000001921032")); System.out.println(questionBankController.createPaper("豆豆", "1000001921051")); System.out.println(questionBankController.createPaper("大寶", "1000001921987")); }
結果:
考生:花花 考號:1000001921032 -------------------------------------------- 1、選擇題 第1題:JAVA所定義的版本中不包括 A:JAVA2 EE B:JAVA2 Card C:JAVA2 ME D:JAVA2 HE E:JAVA2 SE 答案:D 第2題:下列說法正確的是 A:JAVA程序的main方法必須寫在類裏面 B:JAVA程序中能夠有多個main方法 C:JAVA程序中類名必須與文件名同樣 D:JAVA程序的main方法中若是隻有一條語句,能夠不用{}(大括號)括起來 答案:A 第3題:變量命名規範說法正確的是 A:變量由字母、下劃線、數字、$符號隨意組成; B:變量不能以數字做爲開頭; C:A和a在java中是同一個變量; D:不一樣類型的變量,能夠起相同的名字; 答案:B 第4題:如下()不是合法的標識符 A:STRING B:x3x; C:void D:de$f 答案:C 第5題:表達式(11+3*8)/4%3的值是 A:31 B:0 C:1 D:2 答案:D 2、問答題 第1題:小紅馬和小黑馬生的小馬幾條腿 答案:4條腿 第2題:鐵棒打頭疼仍是木棒打頭疼 答案:頭最疼 第3題:什麼牀不能睡覺 答案:牙牀 第4題:爲何好馬不吃回頭草 答案:後面的草沒了 考生:豆豆 考號:1000001921051 -------------------------------------------- 1、選擇題 第1題:JAVA所定義的版本中不包括 A:JAVA2 EE B:JAVA2 Card C:JAVA2 ME D:JAVA2 HE E:JAVA2 SE 答案:D 第2題:下列說法正確的是 A:JAVA程序的main方法必須寫在類裏面 B:JAVA程序中能夠有多個main方法 C:JAVA程序中類名必須與文件名同樣 D:JAVA程序的main方法中若是隻有一條語句,能夠不用{}(大括號)括起來 答案:A 第3題:變量命名規範說法正確的是 A:變量由字母、下劃線、數字、$符號隨意組成; B:變量不能以數字做爲開頭; C:A和a在java中是同一個變量; D:不一樣類型的變量,能夠起相同的名字; 答案:B 第4題:如下()不是合法的標識符 A:STRING B:x3x; C:void D:de$f 答案:C 第5題:表達式(11+3*8)/4%3的值是 A:31 B:0 C:1 D:2 答案:D 2、問答題 第1題:小紅馬和小黑馬生的小馬幾條腿 答案:4條腿 第2題:鐵棒打頭疼仍是木棒打頭疼 答案:頭最疼 第3題:什麼牀不能睡覺 答案:牙牀 第4題:爲何好馬不吃回頭草 答案:後面的草沒了 考生:大寶 考號:1000001921987 -------------------------------------------- 1、選擇題 第1題:JAVA所定義的版本中不包括 A:JAVA2 EE B:JAVA2 Card C:JAVA2 ME D:JAVA2 HE E:JAVA2 SE 答案:D 第2題:下列說法正確的是 A:JAVA程序的main方法必須寫在類裏面 B:JAVA程序中能夠有多個main方法 C:JAVA程序中類名必須與文件名同樣 D:JAVA程序的main方法中若是隻有一條語句,能夠不用{}(大括號)括起來 答案:A 第3題:變量命名規範說法正確的是 A:變量由字母、下劃線、數字、$符號隨意組成; B:變量不能以數字做爲開頭; C:A和a在java中是同一個變量; D:不一樣類型的變量,能夠起相同的名字; 答案:B 第4題:如下()不是合法的標識符 A:STRING B:x3x; C:void D:de$f 答案:C 第5題:表達式(11+3*8)/4%3的值是 A:31 B:0 C:1 D:2 答案:D 2、問答題 第1題:小紅馬和小黑馬生的小馬幾條腿 答案:4條腿 第2題:鐵棒打頭疼仍是木棒打頭疼 答案:頭最疼 第3題:什麼牀不能睡覺 答案:牙牀 第4題:爲何好馬不吃回頭草 答案:後面的草沒了 Process finished with exit code 0
花花
、豆豆
、大寶
,每一個人的試卷內容是同樣的這沒問題,可是三我的的題目以及選項順序都是同樣,就沒有達到咱們說但願的亂序要求。接下來使用原型模式來進行代碼優化,也算是一次很小的重構。
原型模式主要解決的問題就是建立大量重複的類,而咱們模擬的場景就須要給不一樣的用戶都建立相同的試卷,但這些試卷的題目不便於每次都從庫中獲取,甚至有時候須要從遠程的RPC中獲取。這樣都是很是耗時的,並且隨着建立對象的增多將嚴重影響效率。
在原型模式中所須要的很是重要的手段就是克隆,在須要用到克隆的類中都須要實現 implements Cloneable
接口。
itstack-demo-design-4-02 └── src ├── main │ └── java │ └── org.itstack.demo.design │ ├── util │ │ ├── Topic.java │ │ └── TopicRandomUtil.java │ ├── QuestionBank.java │ └── QuestionBankController.java └── test └── java └── org.itstack.demo.design.test └── ApiTest.java
原型模式模型結構
QuestionBank
,題庫中主要負責將各個的題目進行組裝最終輸出試卷。/** * 亂序Map元素,記錄對應答案key * @param option 題目 * @param key 答案 * @return Topic 亂序後 {A=c., B=d., C=a., D=b.} */ static public Topic random(Map<String, String> option, String key) { Set<String> keySet = option.keySet(); ArrayList<String> keyList = new ArrayList<String>(keySet); Collections.shuffle(keyList); HashMap<String, String> optionNew = new HashMap<String, String>(); int idx = 0; String keyNew = ""; for (String next : keySet) { String randomKey = keyList.get(idx++); if (key.equals(next)) { keyNew = randomKey; } optionNew.put(randomKey, option.get(next)); } return new Topic(optionNew, keyNew); }
也就是A的選項內容給B
,B的可能給C
,同時記錄正確答案在處理後的位置信息。public class QuestionBank implements Cloneable { private String candidate; // 考生 private String number; // 考號 private ArrayList<ChoiceQuestion> choiceQuestionList = new ArrayList<ChoiceQuestion>(); private ArrayList<AnswerQuestion> answerQuestionList = new ArrayList<AnswerQuestion>(); public QuestionBank append(ChoiceQuestion choiceQuestion) { choiceQuestionList.add(choiceQuestion); return this; } public QuestionBank append(AnswerQuestion answerQuestion) { answerQuestionList.add(answerQuestion); return this; } @Override public Object clone() throws CloneNotSupportedException { QuestionBank questionBank = (QuestionBank) super.clone(); questionBank.choiceQuestionList = (ArrayList<ChoiceQuestion>) choiceQuestionList.clone(); questionBank.answerQuestionList = (ArrayList<AnswerQuestion>) answerQuestionList.clone(); // 題目亂序 Collections.shuffle(questionBank.choiceQuestionList); Collections.shuffle(questionBank.answerQuestionList); // 答案亂序 ArrayList<ChoiceQuestion> choiceQuestionList = questionBank.choiceQuestionList; for (ChoiceQuestion question : choiceQuestionList) { Topic random = TopicRandomUtil.random(question.getOption(), question.getKey()); question.setOption(random.getOption()); question.setKey(random.getKey()); } return questionBank; } public void setCandidate(String candidate) { this.candidate = candidate; } public void setNumber(String number) { this.number = number; } @Override public String toString() { StringBuilder detail = new StringBuilder("考生:" + candidate + "\r\n" + "考號:" + number + "\r\n" + "--------------------------------------------\r\n" + "1、選擇題" + "\r\n\n"); for (int idx = 0; idx < choiceQuestionList.size(); idx++) { detail.append("第").append(idx + 1).append("題:").append(choiceQuestionList.get(idx).getName()).append("\r\n"); Map<String, String> option = choiceQuestionList.get(idx).getOption(); for (String key : option.keySet()) { detail.append(key).append(":").append(option.get(key)).append("\r\n");; } detail.append("答案:").append(choiceQuestionList.get(idx).getKey()).append("\r\n\n"); } detail.append("2、問答題" + "\r\n\n"); for (int idx = 0; idx < answerQuestionList.size(); idx++) { detail.append("第").append(idx + 1).append("題:").append(answerQuestionList.get(idx).getName()).append("\r\n"); detail.append("答案:").append(answerQuestionList.get(idx).getKey()).append("\r\n\n"); } return detail.toString(); } }
這裏的主要操做內容有三個,分別是;
append()
,對各項題目的添加,有點像咱們在建造者模式中使用的方式,添加裝修物料。clone()
,這裏的核心操做就是對對象的複製,這裏的複製不僅是包括了自己,同時對兩個集合也作了複製。只有這樣的拷貝才能確保在操做克隆對象的時候不影響原對象。list
集合中有一個方法,Collections.shuffle
,能夠將原有集合的順序打亂,輸出一個新的順序。在這裏咱們使用此方法對題目進行亂序操做。public class QuestionBankController { private QuestionBank questionBank = new QuestionBank(); public QuestionBankController() { Map<String, String> map01 = new HashMap<String, String>(); map01.put("A", "JAVA2 EE"); map01.put("B", "JAVA2 Card"); map01.put("C", "JAVA2 ME"); map01.put("D", "JAVA2 HE"); map01.put("E", "JAVA2 SE"); Map<String, String> map02 = new HashMap<String, String>(); map02.put("A", "JAVA程序的main方法必須寫在類裏面"); map02.put("B", "JAVA程序中能夠有多個main方法"); map02.put("C", "JAVA程序中類名必須與文件名同樣"); map02.put("D", "JAVA程序的main方法中若是隻有一條語句,能夠不用{}(大括號)括起來"); Map<String, String> map03 = new HashMap<String, String>(); map03.put("A", "變量由字母、下劃線、數字、$符號隨意組成;"); map03.put("B", "變量不能以數字做爲開頭;"); map03.put("C", "A和a在java中是同一個變量;"); map03.put("D", "不一樣類型的變量,能夠起相同的名字;"); Map<String, String> map04 = new HashMap<String, String>(); map04.put("A", "STRING"); map04.put("B", "x3x;"); map04.put("C", "void"); map04.put("D", "de$f"); Map<String, String> map05 = new HashMap<String, String>(); map05.put("A", "31"); map05.put("B", "0"); map05.put("C", "1"); map05.put("D", "2"); questionBank.append(new ChoiceQuestion("JAVA所定義的版本中不包括", map01, "D")) .append(new ChoiceQuestion("下列說法正確的是", map02, "A")) .append(new ChoiceQuestion("變量命名規範說法正確的是", map03, "B")) .append(new ChoiceQuestion("如下()不是合法的標識符",map04, "C")) .append(new ChoiceQuestion("表達式(11+3*8)/4%3的值是", map05, "D")) .append(new AnswerQuestion("小紅馬和小黑馬生的小馬幾條腿", "4條腿")) .append(new AnswerQuestion("鐵棒打頭疼仍是木棒打頭疼", "頭最疼")) .append(new AnswerQuestion("什麼牀不能睡覺", "牙牀")) .append(new AnswerQuestion("爲何好馬不吃回頭草", "後面的草沒了")); } public String createPaper(String candidate, String number) throws CloneNotSupportedException { QuestionBank questionBankClone = (QuestionBank) questionBank.clone(); questionBankClone.setCandidate(candidate); questionBankClone.setNumber(number); return questionBankClone.toString(); } }
(QuestionBank) questionBank.clone();
,並最終返回試卷信息。編寫測試類:
@Test public void test_QuestionBank() throws CloneNotSupportedException { QuestionBankController questionBankController = new QuestionBankController(); System.out.println(questionBankController.createPaper("花花", "1000001921032")); System.out.println(questionBankController.createPaper("豆豆", "1000001921051")); System.out.println(questionBankController.createPaper("大寶", "1000001921987")); }
結果:
考生:花花 考號:1000001921032 -------------------------------------------- 1、選擇題 第1題:JAVA所定義的版本中不包括 A:JAVA2 Card B:JAVA2 HE C:JAVA2 EE D:JAVA2 ME E:JAVA2 SE 答案:B 第2題:表達式(11+3*8)/4%3的值是 A:1 B:0 C:31 D:2 答案:D 第3題:如下()不是合法的標識符 A:void B:de$f C:STRING D:x3x; 答案:A 第4題:下列說法正確的是 A:JAVA程序的main方法中若是隻有一條語句,能夠不用{}(大括號)括起來 B:JAVA程序中能夠有多個main方法 C:JAVA程序的main方法必須寫在類裏面 D:JAVA程序中類名必須與文件名同樣 答案:C 第5題:變量命名規範說法正確的是 A:變量由字母、下劃線、數字、$符號隨意組成; B:A和a在java中是同一個變量; C:不一樣類型的變量,能夠起相同的名字; D:變量不能以數字做爲開頭; 答案:D 2、問答題 第1題:小紅馬和小黑馬生的小馬幾條腿 答案:4條腿 第2題:什麼牀不能睡覺 答案:牙牀 第3題:鐵棒打頭疼仍是木棒打頭疼 答案:頭最疼 第4題:爲何好馬不吃回頭草 答案:後面的草沒了 考生:豆豆 考號:1000001921051 -------------------------------------------- 1、選擇題 第1題:下列說法正確的是 A:JAVA程序中能夠有多個main方法 B:JAVA程序的main方法必須寫在類裏面 C:JAVA程序的main方法中若是隻有一條語句,能夠不用{}(大括號)括起來 D:JAVA程序中類名必須與文件名同樣 答案:B 第2題:表達式(11+3*8)/4%3的值是 A:2 B:1 C:31 D:0 答案:A 第3題:如下()不是合法的標識符 A:void B:de$f C:x3x; D:STRING 答案:A 第4題:JAVA所定義的版本中不包括 A:JAVA2 Card B:JAVA2 HE C:JAVA2 ME D:JAVA2 EE E:JAVA2 SE 答案:B 第5題:變量命名規範說法正確的是 A:變量不能以數字做爲開頭; B:A和a在java中是同一個變量; C:不一樣類型的變量,能夠起相同的名字; D:變量由字母、下劃線、數字、$符號隨意組成; 答案:A 2、問答題 第1題:什麼牀不能睡覺 答案:牙牀 第2題:鐵棒打頭疼仍是木棒打頭疼 答案:頭最疼 第3題:爲何好馬不吃回頭草 答案:後面的草沒了 第4題:小紅馬和小黑馬生的小馬幾條腿 答案:4條腿 考生:大寶 考號:1000001921987 -------------------------------------------- 1、選擇題 第1題:如下()不是合法的標識符 A:x3x; B:de$f C:void D:STRING 答案:C 第2題:表達式(11+3*8)/4%3的值是 A:31 B:0 C:2 D:1 答案:C 第3題:變量命名規範說法正確的是 A:不一樣類型的變量,能夠起相同的名字; B:變量由字母、下劃線、數字、$符號隨意組成; C:變量不能以數字做爲開頭; D:A和a在java中是同一個變量; 答案:C 第4題:下列說法正確的是 A:JAVA程序的main方法中若是隻有一條語句,能夠不用{}(大括號)括起來 B:JAVA程序的main方法必須寫在類裏面 C:JAVA程序中類名必須與文件名同樣 D:JAVA程序中能夠有多個main方法 答案:B 第5題:JAVA所定義的版本中不包括 A:JAVA2 EE B:JAVA2 Card C:JAVA2 HE D:JAVA2 SE E:JAVA2 ME 答案:C 2、問答題 第1題:爲何好馬不吃回頭草 答案:後面的草沒了 第2題:小紅馬和小黑馬生的小馬幾條腿 答案:4條腿 第3題:什麼牀不能睡覺 答案:牙牀 第4題:鐵棒打頭疼仍是木棒打頭疼 答案:頭最疼 Process finished with exit code 0
從以上的輸出結果能夠看到,每一個人的題目和答案都是差別化的亂序的,以下圖比對結果; - 花花、豆豆、大寶,每一個人的試卷都存在着題目和選項的混亂排序