日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java设计模式透析之 —— 策略(Strategy)

發(fā)布時(shí)間:2025/3/21 java 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java设计模式透析之 —— 策略(Strategy) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/guolin_blog/article/details/8986285


今天你的leader興致沖沖地找到你,希望你可以幫他一個(gè)小忙,他現(xiàn)在急著要去開(kāi)會(huì)。要幫什么忙呢?你很好奇。


他對(duì)你說(shuō),當(dāng)前你們項(xiàng)目的數(shù)據(jù)庫(kù)中有一張用戶信息表,里面存放了很用戶的數(shù)據(jù),現(xiàn)在需要完成一個(gè)選擇性查詢用戶信息的功能。他說(shuō)會(huì)傳遞給你一個(gè)包含許多用戶名的數(shù)組,你需要根據(jù)這些用戶名把他們相應(yīng)的數(shù)據(jù)都給查出來(lái)。


這個(gè)功能很簡(jiǎn)單的嘛,你爽快地答應(yīng)了。由于你們項(xiàng)目使用的是MySQL數(shù)據(jù)庫(kù),你很快地寫出了如下代碼:

[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())?{??
  • ????????????//?處理從數(shù)據(jù)庫(kù)讀出來(lái)的數(shù)據(jù)??
  • ????????}??
  • ????????//?后面應(yīng)將讀到的數(shù)據(jù)組裝成對(duì)象返回,這里略去。??
  • ????}??
  • }??
  • 這里根據(jù)傳入的用戶名數(shù)組拼裝了SQL語(yǔ)句,然后去數(shù)據(jù)庫(kù)中查找相應(yīng)的行。為了方面調(diào)試,你還將拼裝好的SQL語(yǔ)句打印了出來(lái)。


    然后,你寫了如下代碼來(lái)測(cè)試這個(gè)方法:

    [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"?});??
  • ????}??
  • ??
  • }??
  • 現(xiàn)在運(yùn)行一下測(cè)試代碼,你發(fā)現(xiàn)程序出錯(cuò)了。于是你立刻去檢查了一下打印的SQL語(yǔ)句,果然發(fā)現(xiàn)了問(wèn)題。 [sql]?view plaincopy
  • select?*?from?user_info?where?username?=?'Tom'?or?username?=?'Jim'?or?username?=?'Anna'?or???
  • 拼裝出來(lái)的SQL語(yǔ)句在最后多加了一個(gè) or 關(guān)鍵字!因?yàn)閒or循環(huán)執(zhí)行到最后一條數(shù)據(jù)時(shí)不應(yīng)該再加上or,可是代碼很笨地給最后一條數(shù)據(jù)也加了or關(guān)鍵字,導(dǎo)致SQL語(yǔ)句語(yǔ)法出錯(cuò)了。


    這可怎么辦呢?


    有了!你靈光一閃,想出了一個(gè)解決辦法。等SQL語(yǔ)句拼裝完成后,把最后一個(gè)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())?{??
  • ????????????//?處理從數(shù)據(jù)庫(kù)讀出來(lái)的數(shù)據(jù)??
  • ????????}??
  • ????????//?后面應(yīng)將讀到的數(shù)據(jù)組裝成對(duì)象返回,這里略去。??
  • ????}??
  • }??
  • 使用StringBuilder的delete方法,把最后多余的一個(gè)or刪除掉了,這樣再運(yùn)行測(cè)試代碼,一切就正常了,打印的SQL語(yǔ)句如下所示:

    [sql]?view plaincopy
  • select?*?from?user_info?where?username?=?'Tom'?or?username?=?'Jim'?or?username?=?'Anna'??
  • 好了,完工!你自信滿滿。


    你的leader開(kāi)完會(huì)后,過(guò)來(lái)看了下你的成果。總體來(lái)說(shuō),他還挺滿意,但對(duì)于你使用的SQL語(yǔ)句拼裝算法,他總是感覺(jué)有些不對(duì)勁,可是又說(shuō)不上哪里不好。于是他告訴了你另一種拼裝SQL語(yǔ)句的算法,讓你加入到代碼中,但是之前的那種算法也不要?jiǎng)h除,先保留著再說(shuō),然后他又很忙似的跑開(kāi)了。于是,你把他剛剛教你的算法加了進(jìn)去,代碼如下所示:

    [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())?{??
  • ????????????//?處理從數(shù)據(jù)庫(kù)讀出來(lái)的數(shù)據(jù)??
  • ????????}??
  • ????????//?后面應(yīng)將讀到的數(shù)據(jù)組裝成對(duì)象返回,這里略去。??
  • ????}??
  • }??
  • 可以看到,你leader教你的拼裝算法,使用了一個(gè)布爾變量來(lái)控制是否需要加個(gè)or這個(gè)關(guān)鍵字,第一次執(zhí)行for循環(huán)的時(shí)候因?yàn)樵摬紶栔禐閒alse,所以不會(huì)加上or,在循環(huán)的最后將布爾值賦值為true,這樣以后循環(huán)每次都會(huì)在頭部加上一個(gè)or關(guān)鍵字,由于使用了頭部添加or的方法,所以不用再擔(dān)心SQL語(yǔ)句的尾部會(huì)多出一個(gè)or來(lái)。然后你為了將兩個(gè)算法都保留,在findUserInfo方法上加了一個(gè)參數(shù),strategy值為1表示使用第一種算法,strategy值為2表示使用第二種算法。


    這樣測(cè)試代碼也需要改成如下方式:

    [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);??
  • ????}??
  • ??
  • }??
  • 這里你通過(guò)參數(shù)指明了使用第二種算法來(lái)拼裝SQL語(yǔ)句,打印的結(jié)果和使用第一種算法是完全相同的。


    你立刻把你的leader從百忙之中拖了過(guò)來(lái),讓他檢驗(yàn)一下你當(dāng)前的成果,可是他還是一如既往的挑剔。


    “你這樣寫的話,findUserInfo這個(gè)方法的邏輯就太復(fù)雜了,非常不利于閱讀,也不利于將來(lái)的擴(kuò)展,如果我還有第三第四種算法想加進(jìn)去,這個(gè)方法還能看嗎?” ?你的leader指點(diǎn)你,遇到這種情況,就要使用策略模式來(lái)解決,策略模式的核心思想就是把算法提取出來(lái)放到一個(gè)獨(dú)立的對(duì)象中。


    為了指點(diǎn)你,他不顧自己的百忙,開(kāi)始教你如何使用策略模式進(jìn)行優(yōu)化。


    首先定義一個(gè)策略接口:

    [java]?view plaincopy
  • public?interface?Strategy?{??
  • ??
  • ????String?getSQL(String[]?usernames);??
  • ??
  • }??
  • 然后定義兩個(gè)子類都實(shí)現(xiàn)了上述接口,并將兩種拼裝SQL語(yǔ)句的算法分別加入兩個(gè)子類中: [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方法的第二個(gè)參數(shù)改成Strategy對(duì)象,這樣只需要調(diào)用Strategy的getSQL方法就可以獲得拼裝好的SQL語(yǔ)句,代碼如下所示: [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())?{??
  • ????????????//?處理從數(shù)據(jù)庫(kù)讀出來(lái)的數(shù)據(jù)??
  • ????????}??
  • ????????//?后面應(yīng)將讀到的數(shù)據(jù)組裝成對(duì)象返回,這里略去。??
  • ????}??
  • }??
  • 最后,測(cè)試代碼在調(diào)用findUserInfo方法時(shí),只需要顯示地指明需要使用哪一個(gè)策略對(duì)象就可以了: [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語(yǔ)句絲毫不出預(yù)料,如下所示: [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'??
  • 使用策略模式修改之后,代碼的可讀性和擴(kuò)展性都有了很大的提高,即使以后還需要添加新的算法,你也是手到擒來(lái)了!


    策略:它定義了算法家庭,分別封裝起來(lái)。讓它們之間可以互相替換,此模式讓算法的變化,不會(huì)影響到使用算法的客戶。?


    from:?https://blog.csdn.net/guolin_blog/article/details/8986285

    總結(jié)

    以上是生活随笔為你收集整理的Java设计模式透析之 —— 策略(Strategy)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。