《西游降魔》里面的《儿歌三百首》里面有首儿歌叫做《春天在哪里》

歌词是这种:

春天在哪里

春天在哪里

春天就在小朋友的眼睛里

通过俺的渣英语翻译之后是这种:

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 类:

  1. package cn.com.sitefromscrath.service;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import cn.com.sitefromscrath.entity.Result;
  7.  
  8. public class SearchServiceInRealBiz implements SearchService {
  9.  
  10. public List search(String keywords) {
  11.  
  12. int[] idlist = findDocIDs(keywords);
  13. List<Result> results = getResultsByDocIDs(idlist);
  14.  
  15. return results;
  16.  
  17. }
  18. }

当然,你会看到你的eclipse会有错误提示信息:

由于这两个方法未定义。

可是没有关系,eclipse本身自带工具,

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" height="224" width="651">

自己主动生成的代码是这样子的:

实现他们就好啦:)

我们依照先前的开发流程。给出模拟实现先:

  1. package cn.com.sitefromscrath.service;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import cn.com.sitefromscrath.entity.Result;
  7.  
  8. public class SearchServiceInRealBiz implements SearchService {
  9.  
  10. public List search(String keywords) {
  11.  
  12. int[] idlist = findDocIDs(keywords);
  13. List<Result> results = getResultsByDocIDs(idlist);
  14.  
  15. return results;
  16.  
  17. }
  18.  
  19. private List<Result> getResultsByDocIDs(int[] idlist) {
  20. List<Result> results = new ArrayList<Result>(idlist.length);
  21.  
  22. for(int i = 0; i < idlist.length; i++) {
  23. int id = idlist[i];
  24. String title = "result " + id;
  25. String content = "something..................";
  26. results.add(new Result(title, content));
  27. }
  28.  
  29. return results;
  30. }
  31.  
  32. private int[] findDocIDs(String keywords) {
  33. return new int[]{1, 2, 3, 4};
  34. }
  35. }

请记住。每一步我们都应该去做測试,这里就不一一赘述。

比方,我们能够把BeanFactory run一次。看看main方法的输出会不会发生非预期的变化。

如今。尽管我没有执行tomcat查看网页,可是我能肯定,网页所展示的内容一定是正确的。

因为java程序猿的本性发作,我认为写一个DAO层,然后。。。当然是接口和实现分离虾米的。

lucene的实现(模拟阶段):

接口:

  1. package cn.com.sitefromscrath.dao;
  2.  
  3. public interface LuceneDAO {
  4.  
  5. public int[] findDocIDs(String keywords);
  6.  
  7. }

实现:

  1. package cn.com.sitefromscrath.dao;
  2.  
  3. public class LuceneDAOMock implements LuceneDAO {
  4.  
  5. @Override
  6. public int[] findDocIDs(String keywords) {
  7. return new int[]{1, 2, 3, 4};
  8. }
  9.  
  10. }

Mysql的实现(模拟阶段):

接口:

  1. package cn.com.sitefromscrath.dao;
  2.  
  3. import java.util.List;
  4.  
  5. import cn.com.sitefromscrath.entity.Result;
  6.  
  7. public interface MysqlDAO {
  8.  
  9. public List<Result> getResultsByDocIDs(int[] idlist);
  10.  
  11. }

实现:

  1. package cn.com.sitefromscrath.dao;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import cn.com.sitefromscrath.entity.Result;
  7.  
  8. public class MysqlDAOMock implements MysqlDAO {
  9.  
  10. @Override
  11. public List<Result> getResultsByDocIDs(int[] idlist) {
  12. List<Result> results = new ArrayList<Result>(idlist.length);
  13.  
  14. for(int i = 0; i < idlist.length; i++) {
  15. int id = idlist[i];
  16. String title = "result " + id;
  17. String content = "something..................";
  18. results.add(new Result(title, content));
  19. }
  20.  
  21. return results;
  22. }
  23.  
  24. }

然后,我们把 SearchServiceInRealBiz 的代码从新组织一次。将:

  1. package cn.com.sitefromscrath.service;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import cn.com.sitefromscrath.entity.Result;
  7.  
  8. public class SearchServiceInRealBiz implements SearchService {
  9.  
  10. public List search(String keywords) {
  11.  
  12. int[] idlist = findDocIDs(keywords);
  13. List<Result> results = getResultsByDocIDs(idlist);
  14.  
  15. return results;
  16.  
  17. }
  18.  
  19. private List<Result> getResultsByDocIDs(int[] idlist) {
  20. }
  21.  
  22. private int[] findDocIDs(String keywords) {
  23. }
  24. }

替换为:

  1. public class SearchServiceInRealBiz implements SearchService {
  2.  
  3. public List search(String keywords) {
  4.  
  5. // int[] idlist = findDocIDs(keywords);
  6. // List<Result> results = getResultsByDocIDs(idlist);
  7.  
  8. LuceneDAO luceneDAO = new LuceneDAOMock();
  9. int[] idlist = luceneDAO.findDocIDs(keywords);
  10.  
  11. MysqlDAO mysqlDAO = new MysqlDAOMock();
  12. List<Result> results = mysqlDAO.getResultsByDocIDs(idlist);
  13.  
  14. return results;
  15.  
  16. }
  17. }

測试,stdout / eclipse console 输出无误。

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

当然。我们相同会发现一个问题,我们如今的类是模拟的数据啊,以后怎么切换呢?

还好,有工厂。既然我们在工厂里切换了

  1. SearchService

那么,

  1. LuceneDAO
  2. MysqlDAO

相同能够在那里处理,于是,相同运行我上面提到的流程,

从需求開始,我须要一个什么样的方法,那就先定义什么方法,然后利用eclipse工具生成方法的骨架 method skeleton,然后实现它。

首先改写 SearchServiceInRealBiz :

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

然后,实现方法骨架:

  1. package cn.com.sitefromscrath;
  2.  
  3. import java.util.List;
  4.  
  5. import javax.xml.rpc.ServiceFactory;
  6.  
  7. import cn.com.sitefromscrath.dao.LuceneDAO;
  8. import cn.com.sitefromscrath.dao.LuceneDAOMock;
  9. import cn.com.sitefromscrath.dao.MysqlDAO;
  10. import cn.com.sitefromscrath.dao.MysqlDAOMock;
  11. import cn.com.sitefromscrath.entity.Result;
  12. import cn.com.sitefromscrath.service.SearchService;
  13. import cn.com.sitefromscrath.service.SearchServiceMock;
  14. import cn.com.sitefromscrath.service.SearchServiceInRealBiz;
  15.  
  16. public class BeanFactory {
  17.  
  18. public static boolean MOCK = true;
  19.  
  20. public static Object getBean(String id) {
  21. if("searchService".equals(id)) {
  22. if(MOCK) {
  23. return new SearchServiceMock();
  24. } else {
  25. return getSearchService();
  26. }
  27. }
  28.  
  29. throw new RuntimeException("cannot find the bean with id :" + id);
  30. }
  31.  
  32. public static LuceneDAO getLuceneDAO() {
  33. if(MOCK) {
  34. return new LuceneDAOMock();
  35. } else {
  36. throw new RuntimeException("cannot find the LuceneDAO bean");
  37. }
  38. }
  39.  
  40. public static MysqlDAO getMysqlDAO() {
  41. if(MOCK) {
  42. return new MysqlDAOMock();
  43. } else {
  44. throw new RuntimeException("cannot find the MysqlDAO bean");
  45. }
  46. }
  47.  
  48. public static SearchService getSearchService() {
  49. if(MOCK) {
  50. return new SearchServiceMock();
  51. } else {
  52. return new SearchServiceInRealBiz();
  53. }
  54. }
  55.  
  56. public static void main(String ... arg) {
  57. String keywords = "test";
  58. SearchService searchService = (SearchService)BeanFactory.getBean("searchService");
  59. List results = searchService.search(keywords);
  60. for(int i = 0; i < results.size(); i++) {
  61. Result result = (Result) results.get(i);
  62. System.out.print("[" + result.title + "]");
  63. System.out.println(result.content);
  64. }
  65. }
  66.  
  67. }

測试无误。bingo!

I gotta get the GREEN BAR!

!!(JUnit专用~~~)

如今,我開始发现

  1. BeanFactory

有点儿无处不在了,一旦须要改动。哪怕是改个 BeanFactory 的名字,假设没有refactor工具,工作也是相当麻烦的。

这就是所谓的 “上帝类 God Class” “上帝对象 God Object”

为了降低影响。至少,我应该尽可能的把 BeanFactory 的字样从其它类里面移出去。

让我们高唱国际歌,“从来就没有什么救世主,也没有神仙皇帝”,对BeanFactory进行大刀阔斧的革命~~。

在我们如今的代码里,仅有 SearchServiceInRealBiz 拥抱了 “上帝”。 因此。想想办法:

  1. public class SearchServiceInRealBiz implements SearchService {
  2.  
  3. private LuceneDAO luceneDAO;
  4. private MysqlDAO mysqlDAO;
  5.  
  6. private SearchServiceInRealBiz(LuceneDAO luceneDAO, MysqlDAO mysqlDAO) {
  7. super();
  8. this.luceneDAO = luceneDAO;
  9. this.mysqlDAO = mysqlDAO;
  10. }
  11.  
  12. public List search(String keywords) {
  13.  
  14. int[] idlist = luceneDAO.findDocIDs(keywords);
  15. List<Result> results = mysqlDAO.getResultsByDocIDs(idlist);
  16.  
  17. return results;
  18. }
  19. }

当然 BeanFactory 肯定会报错的。



必须说明:我期待这种报错(编译时报错),这样我们才干发现对代码进行调整之后会影响那些地方。然后随之做出相应调整。

參考第二种方式:

  1. private LuceneDAO luceneDAO;
  2. private MysqlDAO mysqlDAO;
  3.  
  4. public void setLuceneDAO(LuceneDAO luceneDAO) {
  5. this.luceneDAO = luceneDAO;
  6. }
  7.  
  8. public void setMysqlDAO(MysqlDAO mysqlDAO) {
  9. this.mysqlDAO = mysqlDAO;
  10. }
  11.  
  12. public List search(String keywords) {
  13.  
  14. int[] idlist = luceneDAO.findDocIDs(keywords);
  15. List<Result> results = mysqlDAO.getResultsByDocIDs(idlist);
  16.  
  17. return results;
  18. }

这样eclipse不会报错。可是。。

。。。。。你失去了改正的机会。

混过了编译时检測,跑不掉执行时报错D,亲!

并且。这个问题会隐蔽的让你吐血~~~~

(事实上,我在暗示你应该在spring的xml中选择哪一种装配方式……)

如今。让我们修复BeanFactory 的报错:

  1. public static SearchService getSearchService() {
  2. if(MOCK) {
  3. return new SearchServiceMock();
  4. } else {
  5. LuceneDAO luceneDAO = getLuceneDAO();
  6. MysqlDAO mysqlDAO = getMysqlDAO();
  7.  
  8. return new SearchServiceInRealBiz(luceneDAO, mysqlDAO);
  9. }
  10. }

RUN一次,ok,没有问题。 I LOVE GREE BAR!

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" height="301" width="452" alt="">

《儿歌三百首》绝非浪得虚名~~

to be continued....

开发,从需求出发 &#183; 之三 春天在哪里的更多相关文章

  1. 开发,从需求出发 &#183; 之四 春天在这里

    首先,我要大字标语表达立场: 你所使用的framework & non-core features,就跟女人穿在身上的衣服一样,越少越好! watermark/2/text/aHR0cDovL ...

  2. 开发,从需求出发 &#183; 之二 造飞机的工厂

    CD镇楼~~! 如今.让我们切换到后端开发者的角度看问题.我们须要做的是实现一下这个类,让它返回真实的业务数据. package cn.com.sitefromscrath.service; impo ...

  3. 吴裕雄--天生自然PythonDjangoWeb企业开发:需求

    开发或者做一个项目,是要有一个需求过来的,而不是无缘无故的,启动一个项目,或者推动整个项目进行下一步迭代.这个需求可能是根据用户反馈增加的,可能是老板提出来的,也有可能是产品经理提出来的,但是无论是什 ...

  4. [eShopOnContainers 学习系列] - 00 - 开发环境需求

    开发环境需求 https://github.com/dotnet-architecture/eShopOnContainers/wiki/00.-Dev-machine-requirements 我的 ...

  5. 开发人员需求能kill杀死其它阻塞自己的会话,测试发现需要alter system权限有风险

    模拟开发人员需求,可以杀死其它阻塞自己的会话1.能有查询阻塞会话确认的权限SQL> grant select on v_$session to testa;SQL> grant selec ...

  6. HBase应用开发回顾与总结系列之三:RowKey行键生成器工具

      所谓RowKey行键生成器,是指通过软件工具制定行键生成策略,并可将策略信息保存成本地策略文件,待需要时再将本地策略文件序列化成行键生成策略对象,传入数据行信息后可自动生成RowKey行键. 那么 ...

  7. DNF邀请码开发再开发方案需求

    一.原因分析:   1.现实原因:主播粉丝量级有限,一定规模粉丝注册消耗完后无法进 行之后合作 2.主播资源有限,能合作主播数量少   3.直播粉丝真实接近核心用户,但是不能将其有效转化为平台流水   ...

  8. 测试开发【提测平台】分享3-正式开发产品需求&项目初始化

    上两个分享主要是介绍和演示基本前后端所要使用的框架,接下来我们将正式进入到[提测平台的开发] 提要先给出依赖和内容点: 提测平台定义和产品原型需求说明 使用github创建代码仓库进行项目管理 Fla ...

  9. iOS开发——项目需求-快速回到当前界面的顶部

    利用UIWindow实现快速到达顶部 如下图,在状态栏添加一个没有颜色的UIWindow(里面添加一个按钮),实现点击这个按钮时能快速的回到当前界面的顶部 核心代码 一.利用UIWindow实现到达顶 ...

随机推荐

  1. ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)

    --------------------------------------------------------------------------------                     ...

  2. [Recompose] Handle React Events as Streams with RxJS and Recompose

    Events are the beginning of most every stream. Recompose provides a createEventHandler function to h ...

  3. EventBus框架原理解析(结合源代码)(上)

    上一篇文章http://blog.csdn.net/crazy__chen/article/details/47425779 和大家一起模仿EventBus的实现机制.和大家一起写出了一个简易的Eve ...

  4. CSS 相对/绝对(relative/absolute)定位与jQuery的控制显示隐藏

    曾经写显示隐藏老是用jq方法控制: dom.show(); dom.hide(); 事实上这样还是有非常多缺陷的. 这是html结构: <div class="holi"&g ...

  5. vue.2.0-自定义全局组件

    App.vue <template> <div id="app"> <h3>welcome vue-loading</h3> < ...

  6. thinkphp里面使用原生php

    thinkphp里面使用原生php Php代码可以和标签在模板文件中混合使用,可以在模板文件里面书写任意的PHP语句代码 ,包括下面两种方式: 使用php标签 例如: {php}echo 'Hello ...

  7. 今天了解了些redis和memcached的知识

    提取于http://www.cnblogs.com/wupeiqi/articles/5132791.html 感谢博主 使用Redis有哪些好处? (1) 速度快,因为数据存在内存中,类似于Hash ...

  8. Magento--修改已存在的订单的运费

    遇到一种情况,需要在下单后再由管理员添加订单运费,然后顾客再付款.那么问题来了,如何给订单添加运费呢?下面是一段代码,可以实现该功能: $orderId = 'your order id';$orde ...

  9. Windows平台下使用pthreads开发多线程应用

    pthreads简介 POSIX 1003.1-2001标准定义了编写多线程应用程序的API(应用程序编程接口),这个接口通常被称为pthreads.在常见的操作系统中,例如Unix.Linux.Ma ...

  10. 第四次python作业——叶耀宗

    设计题2: 1.参考“三国演义”词频统计程序,实现对红楼梦出场人物的频次统计.2.(可选)将红楼梦出场人物的频次统计结果用词云显示. import jieba excludes = {"什么 ...