生活随笔
收集整理的這篇文章主要介紹了
Java设计模式透析之 —— 策略(Strategy)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉載請注明出處:http://blog.csdn.net/guolin_blog/article/details/8986285
今天你的leader興致沖沖地找到你,希望你可以幫他一個小忙,他現在急著要去開會。要幫什么忙呢?你很好奇。
他對你說,當前你們項目的數據庫中有一張用戶信息表,里面存放了很用戶的數據,現在需要完成一個選擇性查詢用戶信息的功能。他說會傳遞給你一個包含許多用戶名的數組,你需要根據這些用戶名把他們相應的數據都給查出來。
這個功能很簡單的嘛,你爽快地答應了。由于你們項目使用的是MySQL數據庫,你很快地寫出了如下代碼:
[java]?view plaincopy
public?class?QueryUtil?{????????public?void?findUserInfo(String[]?usernames)?throws?Exception?{??????????Class.forName("com.mysql.jdbc.Driver");??????????Connection?conn?=?DriverManager.getConnection("jdbc:mysql://localhost:3306/test",?"root",??????????????????"123456");??????????Statement?stat?=?conn.createStatement();??????????StringBuilder?sql?=?new?StringBuilder("select?*?from?user_info?where?");??????????for?(String?user?:?usernames)?{??????????????sql.append("username?=?'");??????????????sql.append(user);??????????????sql.append("'?or?");??????????}??????????System.out.println(sql);??????????ResultSet?resultSet?=?stat.executeQuery(sql.toString());??????????while?(resultSet.next())?{????????????????????????}????????????????}??}??
這里根據傳入的用戶名數組拼裝了SQL語句,然后去數據庫中查找相應的行。為了方面調試,你還將拼裝好的SQL語句打印了出來。
然后,你寫了如下代碼來測試這個方法:
[java]?view plaincopy
public?class?Test?{????????public?static?void?main(String[]?args)?throws?Exception?{??????????QueryUtil?query?=?new?QueryUtil();??????????query.findUserInfo(new?String[]?{?"Tom",?"Jim",?"Anna"?});??????}????}??
現在運行一下測試代碼,你發現程序出錯了。于是你立刻去檢查了一下打印的SQL語句,果然發現了問題。
[sql]?view plaincopy
select?*?from?user_info?where?username?=?'Tom'?or?username?=?'Jim'?or?username?=?'Anna'?or???
拼裝出來的SQL語句在最后多加了一個 or 關鍵字!因為for循環執行到最后一條數據時不應該再加上or,可是代碼很笨地給最后一條數據也加了or關鍵字,導致SQL語句語法出錯了。
這可怎么辦呢?
有了!你靈光一閃,想出了一個解決辦法。等SQL語句拼裝完成后,把最后一個or刪除掉不就好了么。于是你將代碼改成如下所示:
[java]?view plaincopy
public?class?QueryUtil?{????????public?void?findUserInfo(String[]?usernames)?throws?Exception?{??????????Class.forName("com.mysql.jdbc.Driver");??????????Connection?conn?=?DriverManager.getConnection("jdbc:mysql://localhost:3306/test",?"root",??????????????????"123456");??????????Statement?stat?=?conn.createStatement();??????????StringBuilder?sql?=?new?StringBuilder("select?*?from?user_info?where?");??????????for?(String?user?:?usernames)?{??????????????sql.append("username?=?'");??????????????sql.append(user);??????????????sql.append("'?or?");??????????}??????????sql.delete(sql.length()?-?"?or?".length(),?sql.length());??????????System.out.println(sql);??????????ResultSet?resultSet?=?stat.executeQuery(sql.toString());??????????while?(resultSet.next())?{????????????????????????}????????????????}??}??
使用StringBuilder的delete方法,把最后多余的一個or刪除掉了,這樣再運行測試代碼,一切就正常了,打印的SQL語句如下所示:
[sql]?view plaincopy
select?*?from?user_info?where?username?=?'Tom'?or?username?=?'Jim'?or?username?=?'Anna'??
好了,完工!你自信滿滿。
你的leader開完會后,過來看了下你的成果??傮w來說,他還挺滿意,但對于你使用的SQL語句拼裝算法,他總是感覺有些不對勁,可是又說不上哪里不好。于是他告訴了你另一種拼裝SQL語句的算法,讓你加入到代碼中,但是之前的那種算法也不要刪除,先保留著再說,然后他又很忙似的跑開了。于是,你把他剛剛教你的算法加了進去,代碼如下所示:
[java]?view plaincopy
public?class?QueryUtil?{????????public?void?findUserInfo(String[]?usernames,?int?strategy)?throws?Exception?{??????????Class.forName("com.mysql.jdbc.Driver");??????????Connection?conn?=?DriverManager.getConnection("jdbc:mysql://localhost:3306/test",?"root",??????????????????"123456");??????????Statement?stat?=?conn.createStatement();??????????StringBuilder?sql?=?new?StringBuilder("select?*?from?user_info?where?");??????????if?(strategy?==?1)?{??????????????for?(String?user?:?usernames)?{??????????????????sql.append("username?=?'");??????????????????sql.append(user);??????????????????sql.append("'?or?");??????????????}??????????????sql.delete(sql.length()?-?"?or?".length(),?sql.length());??????????}?else?if?(strategy?==?2)?{??????????????boolean?needOr?=?false;??????????????for?(String?user?:?usernames)?{??????????????????if?(needOr)?{??????????????????????sql.append("?or?");??????????????????}??????????????????sql.append("username?=?'");??????????????????sql.append(user);??????????????????sql.append("'");??????????????????needOr?=?true;??????????????}??????????}??????????System.out.println(sql);??????????ResultSet?resultSet?=?stat.executeQuery(sql.toString());??????????while?(resultSet.next())?{????????????????????????}????????????????}??}??
可以看到,你leader教你的拼裝算法,使用了一個布爾變量來控制是否需要加個or這個關鍵字,第一次執行for循環的時候因為該布爾值為false,所以不會加上or,在循環的最后將布爾值賦值為true,這樣以后循環每次都會在頭部加上一個or關鍵字,由于使用了頭部添加or的方法,所以不用再擔心SQL語句的尾部會多出一個or來。然后你為了將兩個算法都保留,在findUserInfo方法上加了一個參數,strategy值為1表示使用第一種算法,strategy值為2表示使用第二種算法。
這樣測試代碼也需要改成如下方式:
[java]?view plaincopy
public?class?Test?{????????public?static?void?main(String[]?args)?throws?Exception?{??????????QueryUtil?query?=?new?QueryUtil();??????????query.findUserInfo(new?String[]?{?"Tom",?"Jim",?"Anna"?},?2);??????}????}??
這里你通過參數指明了使用第二種算法來拼裝SQL語句,打印的結果和使用第一種算法是完全相同的。
你立刻把你的leader從百忙之中拖了過來,讓他檢驗一下你當前的成果,可是他還是一如既往的挑剔。
“你這樣寫的話,findUserInfo這個方法的邏輯就太復雜了,非常不利于閱讀,也不利于將來的擴展,如果我還有第三第四種算法想加進去,這個方法還能看嗎?” ?你的leader指點你,遇到這種情況,就要使用策略模式來解決,策略模式的核心思想就是把算法提取出來放到一個獨立的對象中。
為了指點你,他不顧自己的百忙,開始教你如何使用策略模式進行優化。
首先定義一個策略接口:
[java]?view plaincopy
public?interface?Strategy?{????????String?getSQL(String[]?usernames);????}??
然后定義兩個子類都實現了上述接口,并將兩種拼裝SQL語句的算法分別加入兩個子類中:
[java]?view plaincopy
public?class?Strategy1?implements?Strategy?{????????@Override??????public?String?getSQL(String[]?usernames)?{??????????StringBuilder?sql?=?new?StringBuilder("select?*?from?user_info?where?");??????????for?(String?user?:?usernames)?{??????????????sql.append("username?=?'");??????????????sql.append(user);??????????????sql.append("'?or?");??????????}??????????sql.delete(sql.length()?-?"?or?".length(),?sql.length());??????????return?sql.toString();??????}????}??
[java]?view plaincopy
public?class?Strategy2?implements?Strategy?{????????@Override??????public?String?getSQL(String[]?usernames)?{??????????StringBuilder?sql?=?new?StringBuilder("select?*?from?user_info?where?");??????????boolean?needOr?=?false;??????????for?(String?user?:?usernames)?{??????????????if?(needOr)?{??????????????????sql.append("?or?");??????????????}??????????????sql.append("username?=?'");??????????????sql.append(user);??????????????sql.append("'");??????????????needOr?=?true;??????????}??????????return?sql.toString();??????}????}??
然后把QueryUtil中findUserInfo方法的第二個參數改成Strategy對象,這樣只需要調用Strategy的getSQL方法就可以獲得拼裝好的SQL語句,代碼如下所示:
[java]?view plaincopy
public?class?QueryUtil?{????????public?void?findUserInfo(String[]?usernames,?Strategy?strategy)?throws?Exception?{??????????Class.forName("com.mysql.jdbc.Driver");??????????Connection?conn?=?DriverManager.getConnection("jdbc:mysql://localhost:3306/test",?"root",??????????????????"123456");??????????Statement?stat?=?conn.createStatement();??????????String?sql?=?strategy.getSQL(usernames);??????????System.out.println(sql);??????????ResultSet?resultSet?=?stat.executeQuery(sql);??????????while?(resultSet.next())?{????????????????????????}????????????????}??}??
最后,測試代碼在調用findUserInfo方法時,只需要顯示地指明需要使用哪一個策略對象就可以了:
[java]?view plaincopy
public?class?Test?{????????public?static?void?main(String[]?args)?throws?Exception?{??????????QueryUtil?query?=?new?QueryUtil();??????????query.findUserInfo(new?String[]?{?"Tom",?"Jim",?"Anna"?},?new?Strategy1());??????????query.findUserInfo(new?String[]?{?"Jac",?"Joe",?"Rose"?},?new?Strategy2());??????}????}??
打印出的SQL語句絲毫不出預料,如下所示:
[sql]?view plaincopy
select?*?from?user_info?where?username?=?'Tom'?or?username?=?'Jim'?or?username?=?'Anna'??select?*?from?user_info?where?username?=?'Jac'?or?username?=?'Joe'?or?username?=?'Rose'??
使用策略模式修改之后,代碼的可讀性和擴展性都有了很大的提高,即使以后還需要添加新的算法,你也是手到擒來了!
策略:它定義了算法家庭,分別封裝起來。讓它們之間可以互相替換,此模式讓算法的變化,不會影響到使用算法的客戶。?
from:?https://blog.csdn.net/guolin_blog/article/details/8986285
總結
以上是生活随笔為你收集整理的Java设计模式透析之 —— 策略(Strategy)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。