Shao Fan

          關于JAVA與軟件工程
          posts - 31, comments - 71, trackbacks - 0, articles - 4
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          2006年6月21日

          目前開發人員對系統開發的一個共識是使用三層架構,分為表示層,業務層,和持久層。而這三層之間的依賴關系如何?比較常見的一種看法是

          表示層 --> 業務層 --> 持久層

          這表明了層與層之間的調用關系,表示層通過調用業務層來完成任務,而業務層則調用持久層。從另一個角度來看,一種依賴關系是

          表示層 --> 領域模型(Domain Model) <-- 持久層

          表示層和持久層都應該理解(recognize)領域模型。而領域模型則是業務層的一部分。業務層正是系統的價值所在。雖說表示和持久也很重要,在某些系統中可以說是很關鍵,但是它們的最終目的都是為業務服務,所以業務層應該是系統的核心

          基于以上的認識,在系統設計的時應首先分析需求得到領域模型,找出系統中的實體、對象(靜態的一面),并明確大致的業務流程(動態的一面)。 而另兩層應盡最大努力為業務層服務,且盡量減少業務層受另兩層的限制。


          各層的職責:

          表示層:負責顯示信息,及從系統外部得到輸入。表示層的設計決定系統界面的可用性,及信息輸入和展示的可靠性。表示層只知道如何展示信息,及收集用戶輸入,并不知道該如何對這些輸入進行處理來完成業務。

          業務層:完成業務邏輯。業務層設計決定客戶價值是否能夠得到實現。這是系統的關鍵。外在的表現是功能性。業務層設計和實現的失誤表現在用戶端即功能缺失,功能不可靠等。如果需要對業務層的業務規則進行解耦,則可以使用規則引擎如Drools,把業務規則分離出來。但分離后的業務規則仍屬于業務層。業務層知道如何對用戶輸入進行處理,能夠應用業務規則完成用戶所需的業務,但它不知道數據如何讀取和保存。

          持久層:負責用戶信息的持久化。持久層的失誤表現在外即數據處理(儲存,展示等)不可靠。持久層完全不知道業務,只專注于數據存儲和讀取。所謂持久化并不一定是指數據庫,任何方式的持久化(通過文件,網絡的持久化等)都應由持久層完成。

          各層的設計都會直接影響系統性能。

          三層的體積大小和復雜度在不同的系統中可能會有很大的不同。比如說GOOGLE的搜索引擎,它的界面很簡單,可以想像表示層是比較容易實現的,而它的業務層,關系到處理關鍵字,分析搜索結果,決定排名等,而持久層則要負責處理超大量的數據。業務層和持久層則相當復雜。而有的系統持久層會很小,比如殺毒軟件,媒體播放軟件等。業務層小而另兩層大的例子暫時還沒有想到:)


          posted @ 2007-09-08 19:45 shaofan 閱讀(5132) | 評論 (2)編輯 收藏

          help是一個內置函數,所謂內置函數,就是在Python中被自動加載的函數,任何時候都可以用。參數分兩種:

          • 如果傳一個字符串做參數的話,它會自動搜索以這個字符串命名的模塊,方法,等。
          • 如果傳入的是一個對象,就會顯示這個對象的類型的幫助。

          比如輸入help(’print’),它就會尋找以’print’為名的模塊,類,等,找不到就會看到提示信息。而print在python里是一個保留字,和pass,return同等,而非對象,所以help(print)也會出錯((kkkkkkk))。

          舉個例子:

          1 help(’sys’) #會列出sys模塊的幫助
          2 = [1,2,3]
          3 help(a) #會顯示list的幫助
          4 help(a.append) #會顯示list的append方法的幫助

          python安裝自帶的library reference,2.1節是關于內置函數的。

          Reference Manual的6.6節可以找到關于print的東東。

          posted @ 2007-06-05 06:28 shaofan 閱讀(2769) | 評論 (0)編輯 收藏

          Struts2默認theme是xhtml,它用表格來對表單中的控件進行排版。它也提供一個客戶端的js驗證功能,但是它的js腳本卻有些問題,在某些情況下,前次驗證的提示信息無法被清除,提示信息會不斷的累積顯示在屏幕上。而按照設計,每次提交表單時應只顯示每次驗證的出錯信息。

          它的客戶端驗證的流程大概是這樣,用戶提交表單時,對各個控件的輸入按預先設置的規則進行驗證,如果有問題,則清除表單里原有的出錯提示信息,并寫入新的提示。其設計的功能是把出錯信息寫表格里出錯控件的上方,以便用戶看得更加清楚。問題就出在其用來清除原出錯信息的函數,其代碼是這樣的(在struts.jar的template/xhtml目錄下可以找到):

           1 function clearErrorMessages(form) {
           2 
           3     var table = form.childNodes[1];
           4     iftypeof table == "undefined" ) {
           5         table = form.childNodes[0];
           6     }
           7 
           8     // clear out any rows with an "errorFor" attribute
           9     var rows = table.rows;
          10     var rowsToDelete = new Array();
          11     if (rows == null){
          12         return;
          13     }
          14 
          15     for(var i = 0; i < rows.length; i++) {
          16         var r = rows[i];
          17         if (r.getAttribute("errorFor")) {
          18             rowsToDelete.push(r);
          19         }
          20     }
          21 
          22     // now delete the rows
          23     for (var i = 0; i < rowsToDelete.length; i++) {
          24         var r = rowsToDelete[i];
          25         table.deleteRow(r.rowIndex);
          26         //table.removeChild(rowsToDelete[i]);
          27     }
          28 }


          看這個函數的前三行,它試圖取得form的第1個或第2個子節點,并把它作為table來處理(看接下來的幾行)。要想清除表格里的錯誤信息,首先要取得表格本身,這沒錯,但是如果第1個或第2個子節點不是table的話,腳本就會出錯,造成原出錯信息無法清除,這樣每次提交后的提示信息就會累積在屏幕上。

          要解決這個問題有兩個辦法:
          • 寫代碼時要小心,保證form的第1或2個子節點是table,不要在生成table前加其他代碼。
          • 或,修改xhtml的validation.js,使它總能獲得正確的table元素,重新打包到struts.jar。
          剛看了一下Struts的JIRA,已經有人報告了這個問題(id WW-1802),而且這個bug在2.1版本中已經解決了。

          posted @ 2007-06-03 17:56 shaofan 閱讀(2541) | 評論 (3)編輯 收藏

          假設:用兩者寫一個最小的WEB程序。
          過程可以參照:
          1.struts的就太多了,隨便哪個都可以
          2.python/django可以看limodou寫的Django step by step

           

          Java/Struts/JSP  Python/Django
          開發步驟 1.在web.xml里配置struts的servlet
          2.在struts-config.xml里配置URL和action的映射
          3.寫action
          4.寫JSP
          1.在urls.py里配置URL到方法的映射
          2.寫相應的方法
          3.寫HTML模板
          調用過程 1.根據web.xml的映射調用struts的servlet controller
          2.servlet controller根據struts-config.xml的映射調用相應的action
          3.action處理請求
          4.JSP渲染顯示
          1.根據urls.py的映射調用相應的方法
          2.方法處理請求
          3.HTML渲染顯示


          相比之下前者用了兩層才把一個HTTP請求映射到實際處理的方法:第一次是servlet的映射,第二次是struts action的映射。
          而django則一次就從URL映射到相應的方法了。

          另外一個比較顯著的區別,也是基于java和python的語言上的區別吧,java的所有方法必需包含在一個類中,因此action mapping配置時是映射到類,而action在實現類則應實現事先約定的方法(通過繼承或實現接口)。而django則直接得多,可以直接在配置里寫明處理請求的方法名。


          posted @ 2007-04-06 19:11 shaofan 閱讀(4977) | 評論 (0)編輯 收藏

          DOM (Document Object Model)是一套語言無關的XML解析的接口定義。它定義了在XML解析中需要的類型,方法,以及屬性,比如如何獲得一個XML標簽,如何改變標簽的內容,如何改變它的屬性,等等。

          DOM只是一個定義,并不是具體的實現,它的目的就是為了讓大家在各個平臺上都能用相同的方式來處理XML,這樣一來,我只要了解DOM,基本上在各個平臺上都可以方便的處理XML,而不用重新學習了。比如說,Java, JavaScript, Python都有DOM的實現,用它們來處理XML,方式基本上都是一樣的(當然也有非DOM的XML解析方式)。在Java下,實現DOM的類庫就有很多,比如JDom,Xerces, 用GOOGLE一搜就一大把。現在Java 5.0內置的就是Xerces。而JavaScript本身就內置了DOM的實現。Python也默認安裝了DOM的庫。

          正因為DOM致力于實現各個平臺上對XML一致的處理方式,它定義了一堆自己的接口。因此在用DOM的時候,會有很多非NATIVE的東東。比如說,返回節點的子節點的方法,childNodes,返回的類型是NodeList。我第一次在Java上用,就以為是返回一個List,然后用get(n)方法來取得某元素。而實際上NodeList是用item(n)的方法來取得某元素的。這就讓我覺得很怪。而DOM正是用這種方式來獲得“語言無關”的能力的。

          DOM是用IDL(Interface Definition Language)來定義的。完整的定義可以在這里找到 http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html。IDL也很容易看懂。定義的1.1節列出了所有的接口。

          這些接口里,最重要而且常用的是Node,NodeList,Document,Element,Text,Attr這幾個。DOM把XML文檔看作一棵樹,樹上的每個元素都是Node。每個Node都屬于某個類型,比如Element,attribute,text等。這些類型就表明這個節點在XML文檔里的類型了。

          比如Node里有個屬性:

          ??readonly?attribute?unsigned? short ??nodeType;

          根據這個定義,對于取得的節點,我們就可以通過讀取nodeType這個屬性來判斷這個節點的類型。在Java里,所有的屬性都是用getter來取得的,因此對某節點n,就可以用n.getNodeType()取得它的類型。Node接口里也定義了類型常量:

          ??const?unsigned?short??????ELEMENT_NODE???????????????????=?1;
          ??const?unsigned?short??????ATTRIBUTE_NODE?????????????????=?2;
          ??const?unsigned?short??????TEXT_NODE??????????????????????=?3;
          ??const?unsigned?short??????CDATA_SECTION_NODE?????????????=?4;
          ??const?unsigned?short??????ENTITY_REFERENCE_NODE??????????=?5;
          ??const?unsigned?short??????ENTITY_NODE????????????????????=?6;
          ??const?unsigned?short??????PROCESSING_INSTRUCTION_NODE????=?7;
          ??const?unsigned?short??????COMMENT_NODE???????????????????=?8;
          ??const?unsigned?short??????DOCUMENT_NODE??????????????????=?9;
          ??const?unsigned?short??????DOCUMENT_TYPE_NODE?????????????=?10;
          ??const?unsigned?short??????DOCUMENT_FRAGMENT_NODE?????????=?11;
          ??const?unsigned?short??????NOTATION_NODE??????????????????=?12;

          用這些常量和和n.getNodeType()的結果比較,就可以知道它是不是某種類型。

          Node接口中也定義了一些方法,比如:

          ?Node?????appendChild(in?Node?newChild)????raises(DOMException);

          表明appendChild方法需要一個Node類型的參數,返回一個Node。 具體的說明可以點文檔上的鏈接進去,也很容易看懂。

          Node接口里定義了操縱節點的方法,比如增加子節點,返回父節點,插入新節點,返回節點類型,等等。Document,Element等接口都繼承Node接口,因此在它們上面都可以使用操縱節點的方法。

          Document:代表整個XML文檔。所有DOM元素都不能用類似Java里new的方式來生成,而是要通過調用Document里的相應方法來生成。因此它提供了生成諸如Element, Attr, Text的方法。比如createElement, createTextNode, createComment等。它也提供了名為getElementsByTagName的方法,用來通過標簽名稱來取得其對象。比如getElementByTagName("ul")就可以獲得所有ul標簽。它也提供一些文檔的屬性,比如xmlEncoding,inputEncoding等。它的一個屬性,documentElement代表文檔的根節點。所有對XML元素的操作,基本上都是從Document開始的。

          Element:代表一個XML標簽。它可以有屬性,子標簽,等。比如<ul id="booklist"><li>hello</li></ul>。標簽ul是一個Element,它有一個屬性叫id,屬性的值是booklist。它有一個子結點li。li也是一個標簽,它也有個子節點hello,是一個Text類型的節點。這個接口提供操縱其標簽屬性的方法,比如getAttribute,setAttribute,removeAttribute等。它也提供了和Document中一樣的getElementsByTagName的方法,用來獲得在這個節點下的元素。

          Attr:代表標簽中的屬性。比如上面的id。它也是一個Node。它有名字,值,也可以獲得它的所屬標簽。

          Text:代表一段文字,比如上面的hello,它也一個Node,但比較特殊,它不是直接繼承Node,而是繼承CharacterData接口,后者繼承了Node。但是它不能有子節點。

          用JavaScript給一個例子。假設有一個HTML文檔:

          < html >< head >< title > Try?DOM </ title ></ head >< body >
          < ul >
          < li > hello </ li >
          < li > world </ li >
          </ ul >
          </ body ></ html >

          下面是增加一個li的JavaScript方法:

          ulList? = ?document.getElementsByTagName( " ul " );
          ul?????
          = ?ulList.item( 0 );
          txt????
          = ?document.createTextNode( " I?am?new?li " );
          li?????
          = ?document.createElement( " li " );
          li.appendChild(txt);
          ul.appendChild(li);

          用Java來寫,是這樣:

          NodeList?ulList? = ?document.getElementsByTagName( " ul " );
          Node??????? ul??????
          = ?ulList.item( 0 );
          Text????????? txt???? ?
          = ?document.createTextNode( " I?am?new?li " );
          Element??? li??? ????
          = ?document.createElement( " li " );
          li.appendChild(txt);
          ul.appendChild(li);

          可以看到處理方式和數據類型都是一樣的。如果要了解更多,可以看看DOM的定義,都是IDL。

          posted @ 2007-04-01 18:45 shaofan 閱讀(857) | 評論 (0)編輯 收藏

          我的博客已搬家,請移步到 http://shao-fan.com/blog 閱讀最新內容!


          Ubuntu/Debian中的update-alternative用來對系統中不同版本的同個軟件進行管理。
          比如,系統中可能裝有GNU的Java編譯器,和SUN的Java編譯器。可以用update-alternatives來設置當前使用它們中的哪一個。

          它的原理是在/usr/bin中建立一個link,指向/etc/alternatives中的一個文件,而些文件又是一個link,指向當前使用的命令。比如java命令,查看如下:

           $ which java
          /usr/bin/java
          $ ls -l /usr/bin/java
          lrwxrwxrwx /usr/bin/java -> /etc/alternatives/java
          $ ls -l /etc/alternatives/java
          lrwxrwxrwx /etc/alternatives/java -> /usr/lib/j2re1.5-sun/bin/java
          $ ls -l /usr/lib/j2re1.5-sun/bin/java
          -rwxr-xr-x /usr/lib/j2re1.5-sun/bin/java

          參數--display可以某個軟件的當前配置,如:

           $ /usr/sbin/update-alternatives --display java
          java - status is auto.
          link currently points to /usr/lib/j2re1.5-sun/bin/java
          /usr/lib/kaffe/bin/java - priority 300
          slave java.1.gz: /usr/share/man/man1/java.kaffe.1.gz
          /usr/lib/j2re1.5-sun/bin/java - priority 315
          slave java.1.gz: /usr/lib/j2re1.5-sun/man/man1/java.1.gz
          Current `best' version is /usr/lib/j2re1.5-sun/bin/java.

          status有auto和manual兩種。一旦用戶更改了系統的默認設置,它就變為manual。在auto的狀態下,系統會根據幾套配置的priority來判斷當前應該使用哪套配置。

          每套配置可以設定多個link,它們被稱為slave。上面的例子中,有兩套java的配置。一套是/usr/lib/kafe/bin/java,另一套是/usr/lib/j2re1.5-sun/bin/java,它們各有一個slave。在些例中這些slave設置的是java命令的 manual。當更改了配置時,用man命令查看的幫助也會相應更改。

          參數--config可以用來更改當前的配置。

           $ sudo /usr/sbin/update-alternatives --config java 
          There are 2 alternatives which provide `java'.
          Selection Alternative
          -----------------------------------------------
          1 /usr/lib/kaffe/bin/java
          *+ 2 /usr/lib/j2re1.5-sun/bin/java
          Press enter to keep the default*, or type selection number: 1
          Using `/usr/lib/kaffe/bin/java' to provide `java'.

          參數--install用來設置一套新的配置。具體參見 http://blog.stevenkroon.com/2006/08/29/debian-update-alternatives/

          posted @ 2006-12-25 01:43 shaofan 閱讀(6312) | 評論 (1)編輯 收藏

          Web開發真是越來越有意思了。現在居然可以在JavaScript里直接調用Java寫的方法。大水牛Buffalo的最新版1.2.3發行離現在已有半年時間了,現在才注意到。在客戶端的代碼相當簡單:

          buffalo.remoteCall("userService.listAll",[],function(reply){
           //?不用擔心,reply.getResult會從聰明的判斷服務器端遠程調用的結果類型。
           var?userList?=?reply.getResult();?
           var?firstUserFamilyName?=?userList[0].name.familyName;
          });

          給Web程序加上Buffalo也相當容易。只要下載幾個jar文件放到lib目錄下,外加幾個JS文件,然后在web.xml里加一個Servlet即可。用的時候是需要有個properties文件來定義哪些JAVA方法可以被JS調用。而服務器端的JAVA代碼不需要做任何改動。

          暫時手頭上還想不起來哪些地方會用,但是這個東東可是我很久以前曾經想過的,現在有人實現了,還是很激動人心的啊。Buffalo的主頁是 http://www.amowa.net/buffalo/zh/index.html?。


          posted @ 2006-09-08 03:59 shaofan 閱讀(8926) | 評論 (6)編輯 收藏

          最近因為Globus的原因,不得不用Linux了。以前幾次想學,都因為難得要領放棄了。這次裝了Ubuntu,又碰巧在它的論壇上看到一篇很不錯的教程,終于有些“入門”的感覺了。看來找到合適的教程真的是很重要啊。這幾天用下來,感覺還真的很不錯。用Python寫了個顯示目錄樹的小程序。也不知道有沒有現成的,反正很簡單,剛好就練練手,功能也夠我自己用了:)

          下載Python腳本


          posted @ 2006-08-01 08:57 shaofan 閱讀(1503) | 評論 (0)編輯 收藏

          最近Firefox出了點問題。我這里用http proxy上網,連接設置里要設置相應的proxy。但發現每次重啟ff,連接設置都被重置為“直接連接”。即使改回“通過proxy連接”,下次重啟又被重置了。

          馬上google一把,發現類似的問題大致有兩種解決辦法:
          1.進入safe mode,會出現一個對話框,把三個選項都勾上,重啟。
          2.在地址欄輸入about:config,會出現所有的配置,把要改的改了即可。
          3.直接修改prefs.js文件。

          但這三個方法對偶的FF都不管用。

          最后的解決方法是,刪除
          C:\Documents and Settings\<user name>\Application Data\Mozilla\Firefox\Profiles\<xxxxxxxx.default>\
          下的user.js,然后再修改prefs.js。然后一切都正常了。

          原來,ff最基本的配置文件是prefs.js。而user.js的優先級應該是比prefs.js高,因此每次重啟它都從user.js讀取配置。而通過正常途徑,如在選項菜單里改設置,無法在user.js里保存(不知道為什么)。所以就造成了每次重啟配置被重置的情況,其實就是設置無法被保存。把user.js刪掉以后,ff就從prefs.js里讀取配置了,而且新的設置也可以正常保存。

          不管是從選項菜單里修改配置,還是以上的第二種方法,最終的結果都是配置被保存在prefs.js文件里,效果都是一樣的。

          目前已知的會私自修改FF配置的軟件只有Hide IP Plantium,而以上情況正是在安裝Hide IP Plantium以后出現的。用的時候要注意。

          相關的討論在mozillazine里有很多。不得不承認,這類的英文資源要比中文的多得多。看這里的詳細討論:
          http://forums.mozillazine.org/viewtopic.php?t=413875&postdays=0&postorder=asc&postsperpage=15&start=15

          posted @ 2006-07-24 18:21 shaofan 閱讀(4638) | 評論 (2)編輯 收藏

          1.理解頁面流(flow),理解幾種不同的定位方式:static, relative, absolute等
          Positioning and other definitions:http://css.maxdesign.com.au/floatutorial/definitions.htm ?

          2.HTML頁面表達內容邏輯,把樣式控制寫到CSS文件中

          3.浮動(float)的DIV要配合width屬性來用

          4.怎樣控制層的位置:用float,padding,width,height這些屬性來控制
          Float Tutorial: http://css.maxdesign.com.au/floatutorial/index.htm

          5.設置可見的border或background-color來幫助排版

          6.出現內層的DIV跑到外層之外的情況時,可以在外層DIV的</DIV>前加上一個clear層來解決問題。就是這樣:
          ?? <div class="container">
          ?? ?...
          ?? ?...
          ?? ?<div class="clear"></div>
          ? </div>

          ? css:
          ? .clear{
          ?? ?clear:both;
          ? }

          7.樣式表的選擇符(Selector):
          ?? Type/Class/ID等
          ? Selector Tutorial:http://css.maxdesign.com.au/selectutorial/index.htm

          8.關于表單的樣式設計:
          讓我們更好的設計表單:淺議Web的表單設計 http://tech.163.com/06/0529/04/2I8UPHTB0009158Q.html
          用CSS制作具有親和力的表單 作者:greengnn
          http://www.jluvip.com/blog/article.asp?id=192

          9.各種瀏覽器對各種標簽用不同的方式渲染,如p, h1, ul等,它們會有不同的padding和margin,為了在各種瀏覽器下都正常的顯示,可以把它們清零,如:
          *{
          ?? ?padding:0;
          ?? ?margin:0;
          }

          10.使用list來顯示數據或菜單
          List Tutorial:
          http://css.maxdesign.com.au/listamatic/
          http://css.maxdesign.com.au/listamatic2/
          http://css.maxdesign.com.au/listutorial/

          11.關于各種標準,布局,技巧等的網站:
          網頁設計師:http://www.w3cn.org/
          CSS教程:http://www.netvtm.com/w3s/css/
          網頁制作指導 - 致力于網頁制作知識的普及:http://www.jianzhan8.cn/
          當然還有必不可少的經典論壇blueidea:http://www.blueidea.com/bbs/list.asp?GroupName=%CD%F8%D2%B3%B1%EA%D7%BC%BB%AF%D7%A8%C0%B8

          posted @ 2006-06-21 06:22 shaofan 閱讀(934) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 玛沁县| 河北区| 台山市| 陈巴尔虎旗| 常山县| 瓮安县| 子长县| 连江县| 西藏| 济宁市| 化德县| 龙海市| 信宜市| 宜宾市| 湘潭县| 临武县| 大姚县| 汉川市| 烟台市| 遂昌县| 曲阜市| 阿巴嘎旗| 甘南县| 称多县| 贡觉县| 宁武县| 叶城县| 三明市| 高邑县| 响水县| 昌平区| 沙洋县| 博野县| 阳曲县| 龙川县| 资兴市| 类乌齐县| 岚皋县| 新乐市| 富蕴县| 宁晋县|