開發,從需求出發 · 之三 春天在哪裡

來源:互聯網
上載者:User

標籤:Lucene   style   blog   http   java   color   


《西遊降魔》裡面的《兒歌三百首》裡面有首兒歌叫做《春天在哪裡》

歌詞是這樣的:

春天在哪裡

春天在哪裡

春天就在小朋友的眼睛裡


通過俺的渣英語翻譯之後是這樣的:

where spring is

where spring is

the fucking spring is

in javatar‘s eyes

yo

yo

check it out


我相信,java程式員已經意識到我說的春天是什麼了:)

不過spring跟我們現在說的東東有關係嗎?暫時還沒有-_-b

言歸正傳,開始我們上一章節所說的,把問題搞複雜點兒。


我們假設這個搜尋業務需要lucene和mysql的支援。

通過lucene的檢索獲得文檔ID,然後根據ID去mysql資料庫查詢,獲得文檔的標題和常值內容。


讓我們從需求開始,首先操作 SearchServiceInRealBiz 類:

package cn.com.sitefromscrath.service;import java.util.ArrayList;import java.util.List;import cn.com.sitefromscrath.entity.Result;public class SearchServiceInRealBiz implements SearchService {public List search(String keywords) {int[] idlist = findDocIDs(keywords);List<Result> results = getResultsByDocIDs(idlist);return results;}}

當然,你會看到你的eclipse會有錯誤提示資訊:


因為這兩個方法沒有定義。但是沒有關係,eclipse本身內建工具,

自動產生的程式碼是這樣子的:


實現他們就好啦:)

我們按照先前的開發流程,給出類比實現先:

package cn.com.sitefromscrath.service;import java.util.ArrayList;import java.util.List;import cn.com.sitefromscrath.entity.Result;public class SearchServiceInRealBiz implements SearchService {public List search(String keywords) {int[] idlist = findDocIDs(keywords);List<Result> results = getResultsByDocIDs(idlist);return results;}private List<Result> getResultsByDocIDs(int[] idlist) {List<Result> results = new ArrayList<Result>(idlist.length);for(int i = 0; i < idlist.length; i++) {int id = idlist[i];String title = "result " + id;String content = "something..................";results.add(new Result(title, content));}return results;}private int[] findDocIDs(String keywords) {return new int[]{1, 2, 3, 4};}}
請記住,每一步我們都應該去做測試,這裡就不一一贅述。

比如,我們可以把BeanFactory run一次,看看main方法的輸出會不會發生非預期的變化。

現在,雖然我沒有運行tomcat查看網頁,但是我能肯定,網頁所展示的內容一定是正確的。


由於java程式員的本性發作,我覺得寫一個DAO層,然後。。。當然是介面和實現分離蝦米的。。。

lucene的實現(類比階段):

介面:

package cn.com.sitefromscrath.dao;public interface LuceneDAO {public int[] findDocIDs(String keywords);}

實現:

package cn.com.sitefromscrath.dao;public class LuceneDAOMock implements LuceneDAO {@Overridepublic int[] findDocIDs(String keywords) {return new int[]{1, 2, 3, 4};}}

Mysql的實現(類比階段):

介面:

package cn.com.sitefromscrath.dao;import java.util.List;import cn.com.sitefromscrath.entity.Result;public interface MysqlDAO {public List<Result> getResultsByDocIDs(int[] idlist);}

實現:

package cn.com.sitefromscrath.dao;import java.util.ArrayList;import java.util.List;import cn.com.sitefromscrath.entity.Result;public class MysqlDAOMock implements MysqlDAO {@Overridepublic List<Result> getResultsByDocIDs(int[] idlist) {List<Result> results = new ArrayList<Result>(idlist.length);for(int i = 0; i < idlist.length; i++) {int id = idlist[i];String title = "result " + id;String content = "something..................";results.add(new Result(title, content));}return results;}}

然後,我們把 SearchServiceInRealBiz 的代碼從新組織一次,將:

package cn.com.sitefromscrath.service;import java.util.ArrayList;import java.util.List;import cn.com.sitefromscrath.entity.Result;public class SearchServiceInRealBiz implements SearchService {public List search(String keywords) {int[] idlist = findDocIDs(keywords);List<Result> results = getResultsByDocIDs(idlist);return results;}private List<Result> getResultsByDocIDs(int[] idlist) {}private int[] findDocIDs(String keywords) {}}

替換為:

public class SearchServiceInRealBiz implements SearchService {public List search(String keywords) {//int[] idlist = findDocIDs(keywords);//List<Result> results = getResultsByDocIDs(idlist);LuceneDAO luceneDAO = new LuceneDAOMock();int[] idlist = luceneDAO.findDocIDs(keywords);MysqlDAO mysqlDAO = new MysqlDAOMock();List<Result> results = mysqlDAO.getResultsByDocIDs(idlist);return results;}}

測試,stdout / eclipse console 輸出無誤。

[result 1]something..................[result 2]something..................[result 3]something..................[result 4]something..................

當然,我們同樣會發現一個問題,我們現在的類是類比的資料啊,以後怎麼切換呢?

還好,有工廠。既然我們在工廠裡切換了

SearchService
那麼,
LuceneDAO MysqlDAO
同樣可以在那裡處理,於是,同樣執行我上面提到的流程,

從需求開始,我需要一個什麼樣的方法,那就先定義什麼方法,然後利用eclipse工具產生方法的骨架 method skeleton,然後實現它。

首先改寫 SearchServiceInRealBiz :

然後,實現方法骨架:

package cn.com.sitefromscrath;import java.util.List;import javax.xml.rpc.ServiceFactory;import cn.com.sitefromscrath.dao.LuceneDAO;import cn.com.sitefromscrath.dao.LuceneDAOMock;import cn.com.sitefromscrath.dao.MysqlDAO;import cn.com.sitefromscrath.dao.MysqlDAOMock;import cn.com.sitefromscrath.entity.Result;import cn.com.sitefromscrath.service.SearchService;import cn.com.sitefromscrath.service.SearchServiceMock;import cn.com.sitefromscrath.service.SearchServiceInRealBiz;public class BeanFactory {public static boolean MOCK = true; public static Object getBean(String id) {if("searchService".equals(id)) {if(MOCK) {return new SearchServiceMock();} else {return getSearchService();}}throw new RuntimeException("cannot find the bean with id :" + id);}public static LuceneDAO getLuceneDAO() {if(MOCK) {return new LuceneDAOMock();} else {throw new RuntimeException("cannot find the LuceneDAO bean");}}public static MysqlDAO getMysqlDAO() {if(MOCK) {return new MysqlDAOMock();} else {throw new RuntimeException("cannot find the MysqlDAO bean");}}public static SearchService getSearchService() {if(MOCK) {return new SearchServiceMock();} else {return new SearchServiceInRealBiz();}}public static void main(String ... arg) {String keywords = "test";SearchService searchService = (SearchService)BeanFactory.getBean("searchService");List results = searchService.search(keywords);for(int i = 0; i < results.size(); i++) {Result result = (Result) results.get(i);System.out.print("[" + result.title + "]");System.out.println(result.content);}}}

測試無誤。bingo!

I gotta get the GREEN BAR!!!(JUnit專用~~~)


現在,我開始發現

BeanFactory 
有點兒無處不在了,一旦需要修改,哪怕是改個 BeanFactory 的名字,如果沒有refactor工具,工作也是相當麻煩的。

這就是所謂的 “上帝類 God Class” “上帝對象 God Object”

為了減少影響,至少,我應該儘可能的把 BeanFactory 的字樣從其他類裡面移出去。


讓我們高唱國際歌,“從來就沒有什麼救世主,也沒有神仙皇帝”,對BeanFactory進行大刀闊斧的革命~~!


在我們現在的代碼裡,僅有 SearchServiceInRealBiz 擁抱了 “上帝”。 因此,想想辦法:

public class SearchServiceInRealBiz implements SearchService {private LuceneDAO luceneDAO;private MysqlDAO mysqlDAO;private SearchServiceInRealBiz(LuceneDAO luceneDAO, MysqlDAO mysqlDAO) {super();this.luceneDAO = luceneDAO;this.mysqlDAO = mysqlDAO;}public List search(String keywords) {int[] idlist = luceneDAO.findDocIDs(keywords);List<Result> results = mysqlDAO.getResultsByDocIDs(idlist);return results;}}


當然 BeanFactory 肯定會報錯的,


必須說明:我期待這樣的報錯(編譯時間報錯),這樣我們才能發現對代碼進行調整之後會影響那些地方。然後隨之做出對應調整。

參考另外一種方式:

private LuceneDAO luceneDAO;private MysqlDAO mysqlDAO;public void setLuceneDAO(LuceneDAO luceneDAO) {this.luceneDAO = luceneDAO;}public void setMysqlDAO(MysqlDAO mysqlDAO) {this.mysqlDAO = mysqlDAO;}public List search(String keywords) {int[] idlist = luceneDAO.findDocIDs(keywords);List<Result> results = mysqlDAO.getResultsByDocIDs(idlist);return results;}

這樣eclipse不會報錯,但是。。。。。。。你失去了改正的機會!

混過了編譯時間檢測,跑不掉運行時報錯D,親!而且,這個問題會隱形讓你吐血~~~~

(其實,我在暗示你應該在spring的xml中選擇哪一種裝配方式……)


現在,讓我們修複BeanFactory 的報錯:

public static SearchService getSearchService() {if(MOCK) {return new SearchServiceMock();} else {LuceneDAO luceneDAO = getLuceneDAO();MysqlDAO mysqlDAO = getMysqlDAO();return new SearchServiceInRealBiz(luceneDAO, mysqlDAO);}}

RUN一次,ok,沒有問題。 I LOVE GREE BAR!


《兒歌三百首》絕非浪得虛名~~


to be continued....

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.