开发,从需求出发 · 之三 春天在哪里
《西游降魔》里面的《儿歌三百首》里面有首儿歌叫做《春天在哪里》
歌词是这种:
春天在哪里
春天在哪里
春天就在小朋友的眼睛里
通过俺的渣英语翻译之后是这种:
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本身自带工具,
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" height="224" width="651">
自己主动生成的代码是这样子的:
实现他们就好啦:)
我们依照先前的开发流程。给出模拟实现先:
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 {
@Override
public 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 { @Override
public 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 :
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
然后,实现方法骨架:
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!
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" height="301" width="452" alt="">
《儿歌三百首》绝非浪得虚名~~
to be continued....
开发,从需求出发 · 之三 春天在哪里的更多相关文章
- 开发,从需求出发 · 之四 春天在这里
首先,我要大字标语表达立场: 你所使用的framework & non-core features,就跟女人穿在身上的衣服一样,越少越好! watermark/2/text/aHR0cDovL ...
- 开发,从需求出发 · 之二 造飞机的工厂
CD镇楼~~! 如今.让我们切换到后端开发者的角度看问题.我们须要做的是实现一下这个类,让它返回真实的业务数据. package cn.com.sitefromscrath.service; impo ...
- 吴裕雄--天生自然PythonDjangoWeb企业开发:需求
开发或者做一个项目,是要有一个需求过来的,而不是无缘无故的,启动一个项目,或者推动整个项目进行下一步迭代.这个需求可能是根据用户反馈增加的,可能是老板提出来的,也有可能是产品经理提出来的,但是无论是什 ...
- [eShopOnContainers 学习系列] - 00 - 开发环境需求
开发环境需求 https://github.com/dotnet-architecture/eShopOnContainers/wiki/00.-Dev-machine-requirements 我的 ...
- 开发人员需求能kill杀死其它阻塞自己的会话,测试发现需要alter system权限有风险
模拟开发人员需求,可以杀死其它阻塞自己的会话1.能有查询阻塞会话确认的权限SQL> grant select on v_$session to testa;SQL> grant selec ...
- HBase应用开发回顾与总结系列之三:RowKey行键生成器工具
所谓RowKey行键生成器,是指通过软件工具制定行键生成策略,并可将策略信息保存成本地策略文件,待需要时再将本地策略文件序列化成行键生成策略对象,传入数据行信息后可自动生成RowKey行键. 那么 ...
- DNF邀请码开发再开发方案需求
一.原因分析: 1.现实原因:主播粉丝量级有限,一定规模粉丝注册消耗完后无法进 行之后合作 2.主播资源有限,能合作主播数量少 3.直播粉丝真实接近核心用户,但是不能将其有效转化为平台流水 ...
- 测试开发【提测平台】分享3-正式开发产品需求&项目初始化
上两个分享主要是介绍和演示基本前后端所要使用的框架,接下来我们将正式进入到[提测平台的开发] 提要先给出依赖和内容点: 提测平台定义和产品原型需求说明 使用github创建代码仓库进行项目管理 Fla ...
- iOS开发——项目需求-快速回到当前界面的顶部
利用UIWindow实现快速到达顶部 如下图,在状态栏添加一个没有颜色的UIWindow(里面添加一个按钮),实现点击这个按钮时能快速的回到当前界面的顶部 核心代码 一.利用UIWindow实现到达顶 ...
随机推荐
- Looger级别
Logger级别 日志记录器(Logger)是日志处理的核心组件.log4j具有5种正常级别(Level).日志记录器(Logger)的可用级别Level (不包括自定义级别 Level), 以下内容 ...
- zzulioj--1816--矩形(好题数学)
1816: 矩形 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 88 Solved: 24 SubmitStatusWeb Board Descri ...
- Controller接口控制器
1.Controller简介 Controller控制器,是MVC中的部分C,为什么是部分呢?因为此处的控制器主要负责功能处理部分: 1.收集.验证请求参数并绑定到命令对象: 2.将命令对象交给业务对 ...
- HDU 5889 Barricade (Dijkstra+Dinic)
思路: 首先 先Dijkstra一遍 找出来最短路 不是最短路上的边都不要 然后呢 套个Dinic模板就好了-- 求个最小割 输出 大功告成~~ //By SiriusRen #include < ...
- weex入门(一)
emmmm其实没有接触过weex ,了解一番发现有很多坑,有很多基于weex改良后的框架,比如weexplus等等,基本不用踩多少坑.经过几天的深思熟虑我觉得还是去踩坑,毕竟踩完坑才能真正的了解嘛 w ...
- JS之闭包详细解读
闭包在红宝书中的解释就是:有权访问另一个函数作用域中的变量的函数. 1.变量作用域 全局变量:所有的函数外部定义的变量,它的作用域是整个script. 局部变量:定义在函数体内部的变量,作用域仅限于函 ...
- BZOJ5408: string(广义后缀自动机,LCT)
传送门 解题思路: 首先在后缀树上,确定了一个节点就相当于确定了一个串,那么一个点对应的串在另外一个点对应的串产生贡献,当且仅当这个点在当前点子树内. 那么考虑一个新的点在串中对串答案的贡献在一条树链 ...
- Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-qvc66dfs/supervisor/
# 安装supervisor 出错 pip3 install supervisor # 解决 sudo pip3 install supervisor
- 从零開始的Android新项目7 - Data Binding入门篇
Data Binding自从去年的Google I/O公布到至今,也有近一年的时间了.这一年来,从Beta到如今比較完好的版本号.从Android Studio 1.3到如今2.1.2的支持,能够说D ...
- Codeforces 240E. Road Repairs 最小树形图+输出路径
最小树形图裸题,只是须要记录路径 E. Road Repairs time limit per test 2 seconds memory limit per test 256 megabytes i ...