標籤:
從需求不是一句空話。同樣是在發展過程中真正的。
需求驅動,與極限編程的一些想法和測試驅動開發基本重合。
鑒於該網站的發展是一個比較流行的方向,我會從網站開始,闡述自己的“需求驅動的發展“認識,並擴充到更廣泛的領域。
首先,我們如果一個需求:
我們須要實現一個類似google的網站,使用者通過web瀏覽器訪問,在首頁輸入框中查詢。返回搜尋的結果。
效果例如以所看到的:
STEP 0,通過eclipse建立一個web項目:sitefromscratch。檔案結構所看到的:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >
在WebRoot下新增一個jsp檔案:
<%@ page pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> </head> <body> <h1>search it!</h1> <form action="" method="get"> <input type="text" value="site from scratch" name="keywords" /> <input type="submit" value="search!" /> </form> <table border="1" bordercolor="grey" > <tr> <td>result 1</td><td>something..................</td> </tr> <tr> <td>result 1</td><td>something..................</td> </tr> <tr> <td>result 1</td><td>something..................</td> </tr> <tr> <td>result 1</td><td>something..................</td> </tr> </table> </body></html>
通過瀏覽器訪問 /sitefromscratch/search1.jsp 能夠得到和目標一致的效果。
STEP 2,通過介面所展示的內容,我們能夠大致預計出所須要的資料以及其格式,讓我們增加少量的代碼實現相同的效果:
<%@ page pageEncoding="UTF-8"%><%@page import="java.util.List"%><%@page import="java.util.ArrayList"%><%!class Result {String title;String content;public Result(String title, String content) {this.title = title;this.content = content; }} %><%String keywords = "site from scratch";List results = new ArrayList();results.add(new Result("result 1", "something.................."));results.add(new Result("result 2", "something.................."));results.add(new Result("result 3", "something.................."));results.add(new Result("result 4", "something.................."));%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> </head> <body> <h1>search it!</h1> <form action="" method="get"> <input type="text" value="<%=keywords %>" name="keywords" /> <input type="submit" value="search!" /> </form> <% if(!results.isEmpty()) { %> <table border="1" bordercolor="grey" > <% for(int i = 0; i < results.size(); i++) { Result result = (Result)results.get(i); %> <tr> <td><%=result.title %></td><td><%=result.content %></td> </tr> <% } %> </table> <% } %> </body></html>
這裡,我們構造了一批偽資料(同一時候建立了一個類),並通過相應的運行邏輯,得到了全然一致的展示效果。
STEP 3。如今,該把提交、查詢、結果展示的流程走通了:
<%@ page pageEncoding="UTF-8"%><%@page import="java.util.List"%><%@page import="java.util.ArrayList"%><%!class Result {public String title;public String content;public Result(String title, String content) {this.title = title;this.content = content; }} public List search(String keywords) {List results = new ArrayList();results.add(new Result("result 1", "something.................."));results.add(new Result("result 2", "something.................."));results.add(new Result("result 3", "something.................."));results.add(new Result("result 4", "something.................."));return results;}%><%String keywords = request.getParameter("keywords");if(keywords == null) keywords = "";List results = search(keywords);%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> </head> <body> <h1>search it!</h1> <form action="" method="get"> <input type="text" value="<%=keywords %>" name="keywords" /> <input type="submit" value="search!" /> </form> <% if(!results.isEmpty()) { %> <table border="1" bordercolor="grey" > <% for(int i = 0; i < results.size(); i++) { Result result = (Result)results.get(i); %> <tr> <td><%=result.title %></td><td><%=result.content %></td> </tr> <% } %> </table> <% } %> </body></html>
這裡,我們構造了一個 List search(String keywords)方法,將商務邏輯和頁面展示分離開來。分別置於在jsp檔案裡分離的區塊。
STEP 4,接著。為了保持頁面的簡潔,我們把定義的類和方法提取出來,用包組織起來:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >
package cn.com.sitefromscrath.entity;public class Result {public String title;public String content;public Result(String title, String content) {this.title = title;this.content = content;}}
package cn.com.sitefromscrath.service;import java.util.ArrayList;import java.util.List;import cn.com.sitefromscrath.entity.Result;public class SearchService {public List search(String keywords) {List results = new ArrayList();results.add(new Result("result 1", "something.................."));results.add(new Result("result 2", "something.................."));results.add(new Result("result 3", "something.................."));results.add(new Result("result 4", "something.................."));return results;}}
不出意料。SearchService.java 和 Result.java的代碼就是直接從search.jsp中copy過去的。
值得一提的是,我們新增了一個BeanFactory類,作為原廠模式的一個實現,它簡單的通過指定的ID所相應的類返回產生的執行個體。
例如以下所看到的:
package cn.com.sitefromscrath;import cn.com.sitefromscrath.service.SearchService;public class BeanFactory {public static Object getBean(String id) {if("searchService".equals(id)) {return new SearchService();}throw new RuntimeException("cannot find the bean with id :" + id);}}
儘管它如今看來顯得畫蛇添足了一些,可是在我之後的展開論述中,它將佔有非常重要的位置。
如今。jsp檔案的內容看起來簡潔多了:
<%@ page pageEncoding="UTF-8"%><%@page import="java.util.List"%><%@page import="cn.com.sitefromscrath.service.SearchService"%><%@page import="cn.com.sitefromscrath.BeanFactory"%><%@page import="cn.com.sitefromscrath.entity.Result"%><%String keywords = request.getParameter("keywords");if(keywords == null) keywords = "";SearchService searchService = (SearchService)BeanFactory.getBean("searchService");List results = searchService.search(keywords);%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> </head> <body> <h1>search it!</h1> <form action="" method="get"> <input type="text" value="<%=keywords %>" name="keywords" /> <input type="submit" value="search!" /> </form> <% if(!results.isEmpty()) { %> <table border="1" bordercolor="grey" > <% for(int i = 0; i < results.size(); i++) { Result result = (Result)results.get(i); %> <tr> <td><%=result.title %></td><td><%=result.content %></td> </tr> <% } %> </table> <% } %> </body></html>
STEP 5,聽說MVC是個非常高科技的東西,我們也來實現一下:
新增一個servlet,作為 控制層 Controller
package cn.com.sitefromscrath.web;import java.io.IOException;import java.util.List;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import cn.com.sitefromscrath.BeanFactory;import cn.com.sitefromscrath.service.SearchService;public class SearchServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doPost(request, response);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String keywords = request.getParameter("keywords");if(keywords == null) keywords = "";SearchService searchService = (SearchService)BeanFactory.getBean("searchService");List results = searchService.search(keywords);request.setAttribute("keywords", keywords);request.setAttribute("results", results);request.getRequestDispatcher("/search5.jsp").forward(request, response);}}
新增一個jsp檔案。search5.jsp,作為視圖層 Viewer。
<%@ page pageEncoding="UTF-8"%><%@page import="java.util.List"%><%@page import="cn.com.sitefromscrath.entity.Result"%><%String keywords = (String)request.getAttribute("keywords");List results = (List)request.getAttribute("results");%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> </head> <body> <h1>search it!</h1> <form action="" method="get"> <input type="text" value="<%=keywords %>" name="keywords" /> <input type="submit" value="search!" /> </form> <% if(!results.isEmpty()) { %> <table border="1" bordercolor="grey" > <% for(int i = 0; i < results.size(); i++) { Result result = (Result)results.get(i); %> <tr> <td><%=result.title %></td><td><%=result.content %></td> </tr> <% } %> </table> <% } %> </body></html>
web.xml中配置:
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"><servlet><servlet-name>SearchServlet</servlet-name><servlet-class>cn.com.sitefromscrath.web.SearchServlet</servlet-class></servlet><servlet-mapping><servlet-name>SearchServlet</servlet-name><url-pattern>/search</url-pattern></servlet-mapping><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list></web-app>
如今,讓我們再來run一次,http://localhost:8080/sitefromscratch/search
binggo。效果跟目標無差!
——————————————————————————————————————————————————————————
嗯,到這裡。我們究竟達到了什麼目的?資料還是假的啊,有這個必要嗎?有這個必要嗎?
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >
看看,葛大爺已經被拍了一臉血了。我希望您還沒到這地步。
到了這一步。我們事實上完畢了跟前端頁面製作人員的握手協議:
您寫js的也好,html5的也好,隨便整,我返回的資料格式和內容您也看見了,就這樣。格式不會變,內容也不會出錯。
資料怎麼嵌,那是您的事兒,俺就不侍奉了。
關於”內容不會出錯“這句,補充一點兒,這是指的前端頁面人員(或許是你自己兼任)無需啟動一大堆複雜的應用程式,比方mysql、memcache,就能調試自己的html或者js代碼。同一時候,也避免了其它異常(資料庫down了。資料表毀壞了,網路斷了,memcache串連不上了等等等等)對前端開發的幹擾。
特別是debug階段,假設你不能確保哪些是正確的。你就無法找到錯誤的。
非常多程式猿在debug排查某個問題的時候。最常犯的錯誤就是迷失在一大堆的模組中間,找不到出路,造成這樣的情況的根本原因就在於:在當事人看來,每一個模組都是可疑的,不確定的。要麼猜要麼一個個查,精力和時間就此白白浪費。
而對於後端開發人員來說,如今面臨的就僅僅剩一個任務:讓以下的類方法返回真實的業務結果吧。
package cn.com.sitefromscrath.service;import java.util.ArrayList;import java.util.List;import cn.com.sitefromscrath.entity.Result;public class SearchService {public List search(String keywords) {List results = new ArrayList();results.add(new Result("result 1", "something.................."));results.add(new Result("result 2", "something.................."));results.add(new Result("result 3", "something.................."));results.add(new Result("result 4", "something.................."));return results;}}
我們將在下一章討論這個問題。
|
WEB開發那些事兒 |
|
第一部分:從需求出發 |
|
一 |
所見即所得 (WYSIWYG) |
這裡從一個靜態html頁面說起。逐步抽離出展示層面和資料層面的東西。 |
|
二 |
造飛機的工廠 |
這裡主要說的是Factory 方法。
當然,工廠不是目的,而是結果,需求才是源起。 |
|
三 |
春天在哪裡 |
這裡開始扯到了spring和《兒歌三百首》 |
|
四 |
春天在這裡 |
對spring的吐槽 |
|
五 |
麥克斯韋妖 |
讓我們充當一次麥克斯韋妖。探測和控制單個模組/方法的工作 |
|
六 |
扒皮MVC |
MVC模式的得失。開發的時候。別由於迷失才過程裡爾忘記了我們的目的。
|
|
第二部分:拿起筆來做刀槍 |
|
序 |
序言 |
拿起筆來做刀槍,開發路上當闖將 |
|
一 |
再造一個dom4j |
標題說明了一切 |
|
二 |
再造一個spring |
標題說明了一切 |
|
三 |
再造一個jsp |
標題說明了一切,這裡的 jsp 不是 java server pages,而是java sign pages :) |
|
四 |
再造一個struts |
標題說明了一切 |
|
五 |
再造一個lucene |
標題說明了一切,lucene的原理僅僅須要一句話說清楚,這個就是我喜歡他的原因 |
|
六 |
再造一個hibernate |
事實上我在意的是HQL怎樣映射到多種sql查詢語言上 |
|
七 |
Final Fantasy |
終於的成品 |
著作權聲明:本文部落格原創文章,部落格,未經同意,不得轉載。
發展,需求驅動 · 一間 所見即所得 (WYSIWYG)