91国语精品自产拍,久久人人97超碰精品888,亚洲国产成人私人影院tomhttp://www.aygfsteel.com/java-my-love/category/30329.html家窮人丑,一米四九zh-cnFri, 09 May 2008 00:48:46 GMTFri, 09 May 2008 00:48:46 GMT60面向對象編程思想(轉)http://www.aygfsteel.com/java-my-love/articles/199399.html楊景楊景Fri, 09 May 2008 00:48:00 GMThttp://www.aygfsteel.com/java-my-love/articles/199399.htmlhttp://www.aygfsteel.com/java-my-love/comments/199399.htmlhttp://www.aygfsteel.com/java-my-love/articles/199399.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/199399.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/199399.html我是從學習Java編程開始接觸OOP(面向對象編程),剛開始使用Java編寫程序的時候感覺很別扭,因為我早以習慣用C來編寫程序,很欣賞C的簡潔性和高效性,喜歡C簡練而表達能力豐富的風格,特別忍受不了Java運行起來慢吞吞的速度,相對冗長的代碼,而且一個很簡單的事情,要寫好多類,一個類調用一個類,心里的抵觸情緒很強。

我對Java的面向對象的特性琢磨良久,自認為有所領悟,也開始有意識的運用OOP風格來寫程序,然而還是經常會覺得不知道應該怎樣提煉類,面對一個具體的問題的時候,會覺得腦子里千頭萬緒的,不知道怎么下手,一不小心,又會回到原來的思路上去。

舉個例子,要發廣告郵件,廣告郵件列表存在數據庫里面。倘若用C來寫的話,一般會這樣思考,先把郵件內容讀入,然后連接數據庫,循環取郵件地址,調用本機的qmail的sendmail命令發送。

然后考慮用Java來實現,既然是OOP,就不能什么代碼都塞到main過程里面,于是就設計了三個類:

一個類是負責讀取數據庫,取郵件地址,調用qmail的sendmail命令發送;
一個類是讀郵件內容,MIME編碼成HTML格式的,再加上郵件頭;
一個主類負責從命令讀參數,處理命令行參數,調用發email的類。

把一件工作按照功能劃分為3個模塊分別處理,每個類完成一件模塊任務。

仔細的分析一下,就會發現這樣的設計完全是從程序員實現程序功能的角度來設計的,或者說,設計類的時候,是自低向上的,從機器的角度到現實世界的角度來分析問題的。因此在設計的時候,就已經把程序編程實現的細節都考慮進去了,企圖從底層實現程序這樣的出發點來達到滿足現實世界的軟件需求的目標。

這樣的分析方法其實是不適用于Java這樣面向對象的編程語言,因為,如果改用C語言,封裝兩個C函數,都會比Java實現起來輕松的多,邏輯上也清楚的多。

我覺得面向對象的精髓在于考慮問題的思路是從現實世界的人類思維習慣出發的,只要領會了這一點,就領會了面向對象的思維方法。

舉一個非常簡單的例子:假使現在需要寫一個網頁計數器,客戶訪問一次頁面,網頁計數器加1,計數器是這樣來訪問的

http://hostname/count.cgi?id=xxx

后臺有一個數據庫表,保存每個id(一個id對應一個被統計訪問次數的頁面)的計數器當前值,請求頁面一次,對應id的計數器的字段加1(這里我們忽略并發更新數據庫表,出現的表鎖定的問題)。

如果按照一般從程序實現的角度來分析,我們會這樣考慮:首先是從HTTP GET請求取到id,然后按照id查數據庫表,獲得某id對應的訪問計數值,然后加1,更新數據庫,最后向頁面顯示訪問計數。

現在假設一個沒有程序設計經驗的人,他會怎樣來思考這個問題的呢?他會提出什么樣的需求呢?他很可能會這樣想:

我需要有一個計數器,這個計數器應該有這樣的功能,刷新一次頁面,訪問量就會加1,另外最好還有一個計數器清0的功能,當然計數器如果有一個可以設為任意值的功能的話,我就可以作弊了。

做為一個沒有程序設計經驗的人來說,他完全不會想到對數據庫應該如何操作,對于HTTP變量該如何傳遞,他考慮問題的角度就是我有什么需求,我的業務邏輯是什么,軟件應該有什么功能。

按照這樣的思路(請注意,他的思路其實就是我們平時在生活中習慣的思維方式),我們知道需要有一個計數器類 Counter,有一個必須的和兩個可選的方法:

getCount() // 取計數器值方法
resetCounter() // 計數器清0方法
setCount() // 設計數器為相應的值方法

把Counter類完整的定義如下:

public class Counter {
public int getCount(int id) {}
public void resetCounter(int id) {}
public void setCount(int id, int currentCount) {}
}

解決問題的框架已經有了,來看一下如何使用Counter。 在count.cgi里面調用Counter來計數,程序片斷如下:

// 這里從HTTP環境里面取id值
...
Counter myCounter = new Counter(); // 獲得計數器
int currentCount = myCounter.getCount(id); // 從計數器中取計數
// 這里向客戶瀏覽器輸出
...

程序的框架全都寫好了,剩下的就是實現Counter類方法里面具體的代碼了,此時才去考慮具體的程序語言實現的細節,比如,在getCount()方法里面訪問數據庫,更新計數值。

從上面的例子中看到,面向對象的思維方法其實就是我們在現實生活中習慣的思維方式,是從人類考慮問題的角度出發,把人類解決問題的思維方式逐步翻譯成程序能夠理解的思維方式的過程,在這個翻譯的過程中,軟件也就逐步被設計好了。

在運用面向對象的思維方法進行軟件設計的過程中,最容易犯的錯誤就是開始分析的時候,就想到了程序代碼實現的細節,因此封裝的類完全是基于程序實現邏輯,而不是基于解決問題的業務邏輯。

學習JDBC編程的經典錯誤問法是:“我怎樣封裝對數據庫的select操作?”

面向對象的設計是基于解決業務問題的設計,而不是基于具體編程技術的設計。我不會去封裝select語句的,我只封裝解決問題的業務邏輯,對數據庫的讀取是在業務邏輯的編碼實現階段才去考慮的問題。

回過頭看上面那個發廣告郵件的例子,應該如何應用面向對象的思維方法呢?

對于一個郵件來說,有郵件頭,郵件體,和郵件地址這三個屬性,發送郵件,需要一個發送的方法,另外還需要一個能把所有郵件地址列出來的方法。所以應該如下設計:

類JunkMail

屬性:
head
body
address
方法:
sendMail() // 發送郵件
listAllMail() // 列郵件地址

用Java來表示:

public class JunkMail {
private String head;
private String body;
private String address;
public JunkMain() { // 默認的類構造器
// 從外部配置文件讀郵件頭和郵件體
this.head=...;
this.body=...;
}

public static boolean sendMail(String address) {
// 調用qmail,發送email
}

public static Collection listAllMail() {
// 訪問數據庫,返回一個郵件地址集合
}
}

當把JunkMail設計好了以后,再調用JunkMail類完成郵件的發送,將是非常輕松的事情。

如果說傳統的面向過程的編程是符合機器運行指令的流程的話,那么面向對象的思維方法就是符合現實生活中人類解決問題的思維過程。

在面向對象的軟件分析和設計的時候,要提醒自己,不要一上來就去想程序代碼的實現,應該拋開具體編程語言的束縛,集中精力分析我們要實現的軟件的業務邏輯,分析軟件的業務流程,思考應該如何去描述和實現軟件的業務。畢竟軟件只是一個載體,業務才是我們真正要實現的目標。

但是在設計過程中,心里卻往往在擔心,如果我完全不去考慮程序代碼的實現的話,那么我怎么知道我的設計一定合理呢?我怎么知道我設計的類、接口一定可以實現呢?所以經??梢钥吹降默F象就是:

在設計過程中,雖然知道不能過早考慮代碼實現,但是每設計一個類,一個接口,心里都要不知不覺的用自己熟悉的編程語言大概的評估一下,看看能否編出來,因此,一不小心,就會又回到按照程序功能實現的思路進行設計的老路上去了。

舉個例子來說明,在做Web程序設計的時候,經常要遇到分頁顯示數據的情況。比如說需要把系統中所有的用戶都列出來這樣的功能。假設使用User類來表示用戶,增加用戶addUser(),刪除用戶deleteUser(),查詢所有用戶listUsers()方法。而數據庫中有一個user表,一條記錄是一個用戶的信息。下面考慮一下User類的方法的實現:

addUser()和deleteUser()方法都好實現,就是對數據庫增加記錄和刪除記錄。對于listUsers()方法,其實就是對user表的select,取出一個記錄集。但是該怎么從listUsers()方法中得到所有用戶的列表呢?

一個方法調用的返回值只有一個,沒有多個,所以很多情況下采用的辦法就是返回值定義為集合類型,比如Vector。這樣就可以在listUsers()方法的具體代碼實現的時候,從數據庫依次取出一個個記錄,插入到Vector里面來。在主程序里面,調用listUsers()方法可以返回一個Vector,然后再對Vector遍歷操作,就可以得到用戶列表了。

public class User {

public static void addUser(...) {
// 數據庫insert一條記錄
}

public static void deleteUser(...) {
// 數據庫delete一條記錄
}

public Vector listUsers(...) {
// 數據庫select結果放到一個集合里面
}
}

這樣的設計基本合理,但是仍然有點小問題。因為在設計的時候,就考慮到了用Java的集合類Vector來實現對不定長數據集的存放,因而違反了面向對象設計的一個原則:在設計的時候不應過早的考慮具體程序語言的實現。所以必須用抽象的方法,和具體實現無關的方法來表達業務邏輯。

我們知道,通常對具有集合特征的數據結構進行遍歷通常可以使用next和hasNext方法,next實現取下一個用戶,hasNext判斷是否還有元素。 因此我們定義一個接口Iterator,這個接口中定義兩個方法next和hasNext:

public interface Iterator {
public boolean hasNext() {}
public Object next() {}
}

而User類的listUses方法返回值改為Iterator接口的實現類:

public class User {
...
public Iterator listUsers() {
}
...
}

這樣就把User類的設計和具體的實現方法分離開了,因為此時任何實現了next()和hasNext()方法的類都可以做為listUsers的返回值,都可以被用來表達“用戶列表”,而不僅僅可以使用Vector而已。比如,我可以用ArrayList來表達用戶列表,因為ArrayList也實現了Iterator,當然我也可以自己專門寫一個類來存放用戶列表,只要實現next()和hasNext()方法就行了。

這樣在具體的編寫代碼的時候,程序員具有了最大的靈活性,可以根據具體的情況,采用不同的編程方法來存放用戶列表。特別是降低了程序的耦合度,提高了程序的可移植性。對于上面那個JunkMail的listAllMail()方法也同樣應該改為接口類型。

然后,在主程序里面就這樣來使用User類的listUsers方法:

User myUser = new User();
Iterator iterator = myUser.listUsers();
while (iterator.hasNext()) {
iterator.next();
}

這樣就可以完全不用考慮程序代碼實現了,從高層次上把功能抽象出來,定義成為接口,同時又可以把系統設計的很合理,完全根據業務的需求來進行設計。

結語

通過上面的幾個例子的設計說明,使用面向對象的思維方法,其實是一個把業務邏輯從具體的編程技術當中抽象出來的過程,而這個抽象的過程是自上而下的,非常符合人類的思維習慣,也就是先不考慮問題解決的細節,把問題的最主要的方面抽象成為一個簡單的框架,集中精力思考如何解決主要矛盾,然后在解決問題的過程中,再把問題的細節分割成一個一個小問題,再專門去解決細節問題。

因而一旦牢牢的抓住了這一點,你就會發現在軟件設計和開發過程中,你自己總是會不知不覺的運用面向對象的思維方法來設計和編寫程序,并且程序的設計和開發也變得不再那么枯燥,而一個合理運用面向對象技術進行設計和架構的軟件,更是具備了思維的藝術美感。

最后,愿面向對象的思維方法也能給您的程序設計之路帶來創作的樂趣。



楊景 2008-05-09 08:48 發表評論
]]>
Java項目開發規范(轉)http://www.aygfsteel.com/java-my-love/articles/199396.html楊景楊景Fri, 09 May 2008 00:42:00 GMThttp://www.aygfsteel.com/java-my-love/articles/199396.htmlhttp://www.aygfsteel.com/java-my-love/comments/199396.htmlhttp://www.aygfsteel.com/java-my-love/articles/199396.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/199396.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/199396.html

一、目的   

  對于代碼,首要要求是它必須正確,能夠按照程序員的真實思想去運行;第二個的要求是代碼必須清晰易懂,使別的程序員能夠容易理解代碼所進行的實際工作。在軟件工程領域,源程序的風格統一標志著可維護性、可讀性,是軟件項目的一個重要組成部分。而目前還沒有成文的編碼風格文檔,以致于很多時候,程序員沒有一個共同的標準可以遵守,編碼風格各異,程序可維護性差、可讀性也很差。通過建立代碼編寫規范,形成開發小組編碼約定,提高程序的可靠性、可讀性、可修改性、可維護性、可繼承性和一致性,可以保證程序代碼的質量,繼承軟件開發成果,充分利用資源,使開發人員之間的工作成果可以共享。

    本文在參考業界已有的編碼風格的基礎上,描述了一個基于 JBuilder 的項目風格,力求一種統一的編程風格,并從整體編碼風格、代碼文件風格、函數編寫風格、變量風格、注釋風格等幾個方面進行闡述。(這些規范并不是一定要絕對遵守,但是一定要讓程序有良好的可讀性)


二、整體編碼風格

1、縮進

    縮進建議以4個空格為單位。建議在 Tools/Editor Options 中設置 Editor 頁面的Block ident為4,Tab Size 為8。預處理語句、全局數據、標題、附加說明、函數說明、標號等均頂格書寫。語句塊的"{"、"}"配對對齊,并與其前一行對齊,語句塊類的語句縮進建議每個"{"、"}"單獨占一行,便于匹對。JBuilder 中的默認方式是開始的"{"不是單獨一行,建議更改成上述格式(在 Project/Default Project Properties 中設置 Code Style 中選擇 Braces 為 Next line)。

2、空格

    原則上變量、類、常量數據和函數在其類型,修飾名稱之間適當空格并據情況對齊。關鍵字原則上空一格,如:if ( ... ) 等。運算符的空格規定如下:"::"、"->;"、"["、"]"、"++"、"--"、"~"、"!"、"+"、"-"(指正負號)、"&"(引用)等幾個運算符兩邊不加空格(其中單目運算符系指與操作數相連的一邊),其它運算符(包括大多數二目運算符和三目運算符"?:"兩邊均加一空格,在作函數定義時還可據情況多空或不空格來對齊,但在函數實現時可以不用。","運算符只在其后空一格,需對齊時也可不空或多空格。不論是否有括號,對語句行后加的注釋應用適當空格與語句隔開并盡可能對齊。個人認為此項可以依照個人習慣決定遵循與否。

3、對齊

    原則上關系密切的行應對齊,對齊包括類型、修飾、名稱、參數等各部分對齊。另每一行的長度不應超過屏幕太多,必要時適當換行,換行時盡可能在","處或運算符處,換行后最好以運算符打頭,并且以下各行均以該語句首行縮進,但該語句仍以首行的縮進為準,即如其下一行為“{”應與首行對齊。

    變量定義最好通過添加空格形成對齊,同一類型的變量最好放在一起。如下例所示:
int        Value;
int        Result;
int        Length;
DWORD      Size;
DWORD      BufSize;

 個人認為此項可以依照個人習慣決定遵循與否。

4、空行

 不得存在無規則的空行,比如說連續十個空行。程序文件結構各部分之間空兩行,若不必要也可只空一行,各函數實現之間一般空兩行,由于每個函數還要有函數說明注釋,故通常只需空一行或不空,但對于沒有函數說明的情況至少應再空一行。對自己寫的函數,建議也加上“//------”做分隔。函數內部數據與代碼之間應空至少一行,代碼中適當處應以空行空開,建議在代碼中出現變量聲明時,在其前空一行。類中四個“p”之間至少空一行,在其中的數據與函數之間也應空行。

5、注釋

 注釋是軟件可讀性的具體體現。程序注釋量一般占程序編碼量的20%,軟件工程要求不少于20%。程序注釋不能用抽象的語言,類似于"處理"、"循環"這樣的計算機抽象語言,要精確表達出程序的處理說明。例如:"計算凈需求"、"計算第一道工序的加工工時"等。避免每行程序都使用注釋,可以在一段程序的前面加一段注釋,具有明確的處理邏輯。

 注釋必不可少,但也不應過多,不要被動的為寫注釋而寫注釋。以下是四種必要的注釋:
 
A. 標題、附加說明。

B. 函數、類等的說明。對幾乎每個函數都應有適當的說明,通常加在函數實現之前,在沒有函數實現部分的情況下則加在函數原型前,其內容主要是函數的功能、目的、算法等說明,參數說明、返回值說明等,必要時還要有一些如特別的軟硬件要求等說明。公用函數、公用類的聲明必須由注解說明其使用方法和設計思路,當然選擇恰當的命名格式能夠幫助你把事情解釋得更清楚。

C. 在代碼不明晰或不可移植處必須有一定的說明。

D. 及少量的其它注釋,如自定義變量的注釋、代碼書寫時間等。

  注釋有塊注釋和行注釋兩種,分別是指:"/**/"和"//"建議對A用塊注釋,D用行注釋,B、C則視情況而定,但應統一,至少在一個單元中B類注釋形式應統一。具體對不同文件、結構的注釋會在后面詳細說明。

6、代碼長度

 對于每一個函數建議盡可能控制其代碼長度為53行左右,超過53行的代碼要重新考慮將其拆分為兩個或兩個以上的函數。函數拆分規則應該一不破壞原有算法為基礎,同時拆分出來的部分應該是可以重復利用的。對于在多個模塊或者窗體中都要用到的重復性代碼,完全可以將起獨立成為一個具備公用性質的函數,放置于一個公用模塊中。

7、頁寬

 頁寬應該設置為80字符。源代碼一般不會超過這個寬度, 并導致無法完整顯示, 但這一設置也可以靈活調整. 在任何情況下, 超長的語句應該在一個逗號或者一個操作符后折行. 一條語句折行后, 應該比原來的語句再縮進2個字符.

8、行數

 一般的集成編程環境下,每屏大概只能顯示不超過50行的程序,所以這個函數大概要5-6屏顯示,在某些環境下要8屏左右才能顯示完。這樣一來,無論是讀程序還是修改程序,都會有困難。因此建議把完成比較獨立功能的程序塊抽出,單獨成為一個函數。把完成相同或相近功能的程序塊抽出,獨立為一個子函數??梢园l現,越是上層的函數越簡單,就是調用幾個子函數,越是底層的函數完成的越是具體的工作。這是好程序的一個標志。這樣,我們就可以在較上層函數里容易控制整個程序的邏輯,而在底層的函數里專注于某方面的功能的實現了。


三、代碼文件風格

所有的 Java(*.java) 文件都必須遵守如下的樣式規則:

. 文件生成

對于規范的 JAVA 派生類,盡量用 JBuilder 的 Object Gallery 工具來生成文件格式,避免用手工制作的頭文件/實現文件。
 
. package/import

package 行要在 import 行之前,import 中標準的包名要在本地的包名之前,而且按照字母順序排列。如果 import 行中包含了同一個包中的不同子目錄,則應該用 * 來處理。

package hotlava.net.stats;

import java.io.*;
import java.util.Observable;
import hotlava.util.Application; 
 
這里 java.io.* 使用來代替InputStream and OutputStream 的。

. 文件頭部注釋

文件頭部注釋主要是表明該文件的一些信息,是程序的總體說明,可以增強程序的可讀性和可維護性。文件頭部注釋一般位于 package/imports 語句之后,Class 描述之前。要求至少寫出文件名、創建者、創建時間和內容描述。JBuilder 的 Object Gallery 工具生成的代碼中會在類、工程文件中等自動添加注釋,我們也要添加一些注釋,其格式應該盡量約束如下:

/**
 * Title:  確定鼠標位置類
 * Description: 確定鼠標當前在哪個作業欄位中并返回作業號
 * @Copyright: Copyright (c) 2002
 * @Company: HIT
 * @author: rivershan
 * @version: 1.0
 * @time: 2002.10.30
 */
 
. Class

接下來的是類的注釋,一般是用來解釋類的。

/**
 * A class representing a set of packet and byte counters
 * It is observable to allow it to be watched, but only
 * reports changes when the current set is complete
 */
 
接下來是類定義,包含了在不同的行的 extends 和 implements

public class CounterSet
  extends Observable
  implements Cloneable

.Class Fields

接下來是類的成員變量:

/**
 * Packet counters
 */
 
protected int[] packets;
 
public 的成員變量必須生成文檔(JavaDoc)。proceted、private和 package 定義的成員變量如果名字含義明確的話,可以沒有注釋。

. 存取方法
 
接下來是類變量的存取的方法。它只是簡單的用來將類的變量賦值獲取值的話,可以簡單的寫在一行上。(個人認為盡量分行寫)

/**
 * Get the counters
 * @return an array containing the statistical data.  This array has been
 * freshly allocated and can be modified by the caller.
 */
 
public int[] getPackets()
{
  return copyArray(packets, offset);
}

public int[] getBytes()
{
 return copyArray(bytes, offset);
}

public int[] getPackets()
{
 return packets;
}

public void setPackets(int[] packets)
{
 this.packets = packets;
}
 
其它的方法不要寫在一行上

. 構造函數

接下來是構造函數,它應該用遞增的方式寫(比如:參數多的寫在后面)。

訪問類型("public","private" 等.)和任何"static","final"或"synchronized"應該在一行中,并且方法和參數另寫一行,這樣可以使方法和參數更易讀。

public
CounterSet(int size)
{
   this.size = size;
}

. 克隆方法
 
如果這個類是可以被克隆的,那么下一步就是 clone 方法:

public
Object clone()
{
 try
   {
     CounterSet obj = (CounterSet)super.clone();
     obj.packets = (int[])packets.clone();
     obj.size = size;
     return obj;
   } 
   catch(CloneNotSupportedException e)
   {
    throw new InternalError("Unexpected CloneNotSUpportedException: "
          + e.getMessage());
   }
}

. 類方法

下面開始寫類的方法:

/**
 * Set the packet counters
 * (such as when restoring from a database)
 */
protected final
void setArray(int[] r1, int[] r2, int[] r3, int[] r4)
  throws IllegalArgumentException
{
 //
   // Ensure the arrays are of equal size
   //
   if (r1.length != r2.length || r1.length != r3.length || r1.length != r4.length)
  throw new IllegalArgumentException("Arrays must be of the same size");
   System.arraycopy(r1, 0, r3, 0, r1.length);
   System.arraycopy(r2, 0, r4, 0, r1.length);
}

. toString 方法

無論如何,每一個類都應該定義 toString 方法:

public
String toString()
{
 String retval = "CounterSet: ";
    for (int i = 0; i < data.length(); i++)
    {
       retval += data.bytes.toString();
       retval += data.packets.toString();
    }
    return retval;
}

. main 方法

如果main(String[]) 方法已經定義了, 那么它應該寫在類的底部.


四、函數編寫風格

. 函數的命名

通常,函數的命名也是以能表達函數的動作意義為原則的,一般是由動詞打頭,然后跟上表示動作對象的名詞,各單詞的首字母應該大寫。另外,還有一些函數命名的通用規則。如取數,則用Get打頭,然后跟上要取的對象的名字;設置數,則用Set打頭,然后跟上要設的對象的名字;而對象中為了響應消息進行動作的函數,可以命名為On打頭,然后是相應的消息的名稱;進行主動動作的函數,可以命名為Do打頭,然后是相應的動作名稱。類似的規則還有很多,需要程序員多讀優秀的程序,逐漸積累經驗,才能作出好的函數命名。

. 函數注釋

系統自動生成的函數,如鼠標動作響應函數等,不必太多的注釋和解釋;

對于自行編寫的函數,若是系統關鍵函數,則必須在函數實現部分的上方標明該函數的信息,格式如下:

/**
* 函數名:
* 編寫者:
* 參考資料:
* 功  能:
* 輸入參數:
* 輸出參數:
* 備  注:
*/

希望盡量遵循以上格式。


五、符號風格

. 總體要求

對于各種符號的定義,都有一個共通點,就是應該使用有實際意義的英文單詞或英文單詞的縮寫,不要使用簡單但沒有意義的字串,盡可能不使用阿拉伯數字,更切忌使用中文拼音的首字母。如這樣的名稱是不提倡的:Value1,Value2,Value3,Value4 …。

例如:
file(文件),code(編號),data(數據),pagepoint(頁面指針), faxcode(傳真號) ,address(地址),bank(開戶銀行),……

. 變量名稱

變量命名由(前綴+修飾語)構成?,F在比較流行的是一套由微軟的一個匈牙利軟件工程師首先使用,并且在微軟推廣開來,現在被稱之為匈牙利命名法的命名規則。匈牙利命名法規定,使用表示標識符所對應的變量類型的英文小寫縮寫作為標識符的前綴,后面在使用表示變量意義的英文單詞或縮寫進行命名。下面是匈牙利命名法中的一些命名方式:

(1)生存期修飾:用l(local)表示局域變量,p(public)表示全局變量,s(send)表示參數變量

(2)類型修飾:用s(AnsiString)表示字符串,c(char)表示字符,n(number)數值,i(intger)表示整數,d(double)表示雙精度,f(float)浮點型,b(bool)布爾型,d(date)表示日期型.

例如:
li_length表示整形的局域變量,是用來標識長度的.ls_code表示字符型的局域變量,用來標識代碼.

. 控件名稱

控件命名由(前綴+修飾語)構成。前綴即為控件的名稱。

按鈕變量  Button+Xxxxxxx    例如:ButtonSave,ButtonExit,ButtonPrint等
題標變量  Label+Xxxxxxxx    例如:LabelName,LabelSex等
數據表變量 Table+Xxxxxx      例如:TableFile,TableCount等
查詢變量  Query+Xxxxxx      例如:QueryFile,QueryCeneter等
數據源變量 DataSource+Xxx      例如:DataSourceFile,DataSourceCenter等
。。。。。。。。。。。。。。。。
(注:對于與表有關的控件“修飾語”部分最好直接用表名。)

. Package 的命名

Package 的名字應該都是由一個小寫單詞組成。

. Class 的命名

Class 的名字必須由一個或數個能表達該類的意思的大寫字母開頭而其它字母都小寫的單詞或縮寫組成,這樣能使這個 Class 的名稱能更容易被理解。

. Class 變量的命名

變量的名字必須用一個小寫字母開頭。后面的單詞用大寫字母開頭。對于類的成員變量,在對其標識符命名時,要加上代表member(成員)的前綴m_。例如一個標識符為m_dwFlag,則它表示的變量是一個類型為雙字的成員變量,它是代表一個標志。

. Static Final 變量的命名

Static Final 變量的名字應該都大寫,并且指出完整含義。

. 參數的命名

參數的名字必須和變量的命名規范一致。

. 數組的命名

數組應該總是用下面的方式來命名:
byte[] buffer; 
 
而不是:
byte buffer[];

. 方法的參數
 
使用有意義的參數命名,如果可能的話,使用和要賦值的字段一樣的名字:

SetCounter(int size)
{
 this.size = size;
}

. 神秘的數

首先要說什么是神秘的數。我們在程序里經常會用到一些量,它是有特定的含義的。例如,現在我們寫一個薪金統計程序,公司員工有50人,我們在程序里就會用50這個數去進行各種各樣的運算。在這里,50就是&quot;神秘的數&quot;。為什么稱它為神秘呢?因為別的程序員在程序里看到50這個數,不知道它的含義,只能靠猜了。

在程序里出現&quot;神秘的數&quot;會降低程序的可讀性,應該盡量避免。避免的方法是把神秘的數定義為一個常量。注意這個常量的命名應該能表達該數的意義,并且應該全部大寫,以與對應于變量的標識符區別開來。例如上面50這個數,我們可以定義為一個名為NUMOFEMPLOYEES的常量來代替。這樣,別的程序員在讀程序的時候就可以容易理解了。

六、程序編寫風格

. exit()

exit 除了在 main 中可以被調用外,其他的地方不應該調用。因為這樣做不給任何代碼代碼機會來截獲退出。一個類似后臺服務地程序不應該因為某一個庫模塊決定了要退出就退出。

. 異常

申明的錯誤應該拋出一個RuntimeException或者派生的異常。
頂層的main()函數應該截獲所有的異常,并且打印(或者記錄在日志中)在屏幕上。

. 垃圾收集

JAVA使用成熟的后臺垃圾收集技術來代替引用計數。但是這樣會導致一個問題:你必須在使用完對象的實例以后進行清場工作。比如一個prel的程序員可能這么寫:

 ...
 {
  FileOutputStream fos = new FileOutputStream(projectFile);
  project.save(fos, &quot;IDE Project File&quot;);
 }
 ...
 
除非輸出流一出作用域就關閉,非引用計數的程序語言,比如JAVA,是不能自動完成變量的清場工作的。必須象下面一樣寫:

 FileOutputStream fos = new FileOutputStream(projectFile);
 project.save(fos, &quot;IDE Project File&quot;);
 fos.close();

. Clone

下面是一種有用的方法:
implements Cloneable

public
Object clone()
{
 try
 {
  ThisClass obj = (ThisClass)super.clone();
  obj.field1 = (int[])field1.clone();
  obj.field2 = field2;
  return obj;
 }
 catch(CloneNotSupportedException e)
 {
  throw new InternalError(&quot;Unexpected CloneNotSUpportedException: &quot; + e.getMessage());
 }
}

. final 類

絕對不要因為性能的原因將類定義為 final 的(除非程序的框架要求)
如果一個類還沒有準備好被繼承,最好在類文檔中注明,而不要將她定義為 final 的。這是因為沒有人可以保證會不會由于什么原因需要繼承她。
 
. 訪問類的成員變量
 
大部分的類成員變量應該定義為 protected 的來防止繼承類使用他們。
注意,要用&quot;int[] packets&quot;,而不是&quot;int packets[]&quot;,后一種永遠也不要用。

public void setPackets(int[] packets)
{
 this.packets = packets;
}
CounterSet(int size)
{
 this.size = size;
}

. byte 數組轉換到 characters

為了將 byte 數組轉換到 characters,你可以這么做:

&quot;Hello world!&quot;.getBytes();

. Utility 類

Utility 類(僅僅提供方法的類)應該被申明為抽象的來防止被繼承或被初始化。

. 初始化
 
下面的代碼是一種很好的初始化數組的方法:

objectArguments = new Object[]
{
 arguments
};

. 枚舉類型
 
JAVA 對枚舉的支持不好,但是下面的代碼是一種很有用的模板:

class Colour
{
   public static final Colour BLACK = new Colour(0, 0, 0);
   public static final Colour RED = new Colour(0xFF, 0, 0);
   public static final Colour GREEN = new Colour(0, 0xFF, 0);
   public static final Colour BLUE = new Colour(0, 0, 0xFF);
   public static final Colour WHITE = new Colour(0xFF, 0xFF, 0xFF);
}
 
這種技術實現了RED, GREEN, BLUE 等可以象其他語言的枚舉類型一樣使用的常量。 他們可以用 '==' 操作符來比較。
但是這樣使用有一個缺陷:如果一個用戶用這樣的方法來創建顏色 BLACK

new Colour(0,0,0)

那么這就是另外一個對象,'=='操作符就會產生錯誤。她的 equal() 方法仍然有效。由于這個原因,這個技術的缺陷最好注明在文檔中,或者只在自己的包中使用。

. 混合使用 AWT 和 Swing 組件

如果要將 AWT 組件和 Swing 組件混合起來使用的話,請小心使用。實際上,盡量不要將他們混合起來使用。

. 滾動的 AWT 組件

AWT 組件絕對不要用 JscrollPane 類來實現滾動。滾動 AWT 組件的時候一定要用 AWT ScrollPane 組件來實現。

. 避免在 InternalFrame 組件中使用 AWT 組件
 
盡量不要這么做,要不然會出現不可預料的后果。

. Z-Order 問題

AWT 組件總是顯示在 Swing 組件之上。當使用包含 AWT 組件的 POP-UP 菜單的時候要小心,盡量不要這樣使用。


八、性能

 在寫代碼的時候,從頭至尾都應該考慮性能問題。這不是說時間都應該浪費在優化代碼上,而是我們時刻應該提醒自己要注意代碼的效率。比如:如果沒有時間來實現一個高效的算法,那么我們應該在文檔中記錄下來,以便在以后有空的時候再來實現她。

 不是所有的人都同意在寫代碼的時候應該優化性能這個觀點的,他們認為性能優化的問題應該在項目的后期再去考慮,也就是在程序的輪廓已經實現了以后。

. 不必要的對象構造

不要在循環中構造和釋放對象

. 使用 StringBuffer 對象

在處理 String 的時候要盡量使用 StringBuffer 類,StringBuffer 類是構成 String 類的基礎。String 類將 StringBuffer 類封裝了起來,(以花費更多時間為代價)為開發人員提供了一個安全的接口。當我們在構造字符串的時候,我們應該用 StringBuffer 來實現大部分的工作,當工作完成后將 StringBuffer 對象再轉換為需要的 String 對象。比如:如果有一個字符串必須不斷地在其后添加許多字符來完成構造,那么我們應該使用 StringBuffer 對象和她的 append() 方法。如果我們用 String 對象代替 StringBuffer 對象的話,會花費許多不必要的創建和釋放對象的 CPU 時間。

. 避免太多的使用 synchronized 關鍵字

避免不必要的使用關鍵字 synchronized,應該在必要的時候再使用她,這是一個避免死鎖的好方法。

                                                                                  rivershan 原創



楊景 2008-05-09 08:42 發表評論
]]>
使用Hibernate的7個步驟http://www.aygfsteel.com/java-my-love/articles/196968.html楊景楊景Mon, 28 Apr 2008 14:33:00 GMThttp://www.aygfsteel.com/java-my-love/articles/196968.htmlhttp://www.aygfsteel.com/java-my-love/comments/196968.htmlhttp://www.aygfsteel.com/java-my-love/articles/196968.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/196968.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/196968.html面試遇到這個問題,搞了半天就這些東西
Hibernate.cfg.xml文件必須被放在你的classpath里。

在你的程序里使用hibernate必須有下面幾個步驟:

1、建立一個Hibernate configuration對象

2、使用Hibernate configuration對象來建立一個Hibernate factory對象。

3、使用Hibernate factory對象來建立一個Hibernate session對象。

4、使用Hibernate session對象來開始一個事務(可選)

5、使用Hibernate session對象來建立、讀取、更新、刪除數據庫里的數據

6、提交事務(可選)

7、關閉session

Hibernate最佳實踐是建立和緩存Hibernate factory來提高性能。所以我們最好在第一步和第二步建立一

個Struts plug-in 來在servlet context中緩存Hibernate factory。如List5所示:

Hibernate是一個功能非常強大的產品,還有一些未知的功能留給你們去發現。我們簡單的例子只是關于

讀這個行為,但是CRUD里的其它功能也是一樣的簡單。功能性的更新和讀取指定對象一樣簡單,調用

JavaBean setter,調用session的commit方法。Hibernate負責幫你生成SQL語句并且更新數據庫。一個刪

除也是非常的簡單—session.delete(element)便是所有要做的!最后建立只是需要初始化對象,調用

setters方法,然后調用session.save(element)。

Hibernate最佳實踐推薦緩存Hibernate factory對象。我們選擇通過Struts plug-in來建立并且緩存

factory。你也可以選擇使用其它方法在你的類里緩存它。

雖然這個摘錄能很好的滿足你的需要,它還有其它的一些缺點。第一,我們在Struts Action里使用了

Hibernate。遷移到其它的持久層框架上便將需要我們改變每個使用Hibernate的Action。第二,我們的持

久層緊密的與表示層連接。這種關聯使我們在其它表示層機制中沒有重新使用持久層邏輯的機會,例如批

處理程序。

雖然有許多改進的空間,當你不需要重用表現層的時候,這個摘錄還是很適合的。



楊景 2008-04-28 22:33 發表評論
]]>
JSP知識要點(轉)http://www.aygfsteel.com/java-my-love/articles/191030.html楊景楊景Sun, 06 Apr 2008 05:50:00 GMThttp://www.aygfsteel.com/java-my-love/articles/191030.htmlhttp://www.aygfsteel.com/java-my-love/comments/191030.htmlhttp://www.aygfsteel.com/java-my-love/articles/191030.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/191030.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/191030.html 1.必須繼承自HttpServlet
2.必須實現doGet()或者doPost()
3.必須在web.xml中配置Servlet
<servlet>
<servlet-name> </servlet-name>
<servlet-class> </servlet-class>
</servlet>
<servlet-mapping>
<servlet-name> </servlet-name>
<url-pattern> </url-pattern>
</servelt-mapping>

HttpServeltRrequest:請求對象
getParameter():獲得表單元素的值
getAttribute():獲得request范圍中的屬性值
setAttribute():設置reqeust范圍中的屬性值
setCharacterEncoding():設置字符編碼

HttpSerletResponse:相應對象
sendRedirect():外部跳轉
getWriter():獲得輸出流對象
setContentType("text/html; charset=utf-8"):設置相應內容格式和編碼

四種會話跟蹤方式:
1.Session
HttpSession session = request.getSession();
session.setAttribute("name", "zhangsan");
session.setAttribute("pwd", "aaa");
String name = (String) session.getAttribute("name");

2.cookie:
//創建Cookie
Cookie cookie = new Cookie("name", "zhangsan");
//設置Cookie的超時時間
cookie.setMaxAge(24 * 60 * 60 *60);
//把Cookie發送到客戶端
response.addCookie(cookie);

//得到客戶端發送的Cookie
Cookie [] cookies = request.getCookies();
for(int i=0; i <cookies.length; i++) {
   Cookie temp = cookies[i];
   String key = temp.getName();
   String value = temp.getValue();
}

3.隱藏表單域
<input type="hidden" name="name" value="zhangsan" />
request.getParameter("name");

4.Url重寫
問號傳參
LoginServlet?username=zhangsan&pwd=123
String name = request.getParameter("username");
String pwd =request.getPareameter("pwd");

內部跳轉:
LoginServlet
request.getRequestDispatcher("index.jsp").forward(request, resposne);
外部跳轉:
response.sendRedirect("index.jsp");
內部跳轉是一次請求和一次響應
外部跳轉是兩次請求和兩次響應

ServletContext:Servlet上下文對象
它是一個公共區域,可以被所有的客戶端共享
setAttribute():向公共區域里放入數據
getAttribute():從公共區域里取數據

二:
三:三個標準范圍:request, session, ServletContext
   共同點:都有setAttribute(), getAttribute()
   區別:范圍不同,request  < session  < servletContext
四:四種會話跟蹤方式
五:服務器上的五大對象
   request, response, servlet, session, servletContext
   
Jsp:Java Server Page
頁面構成:7種元素
1.靜態內容:html
2.指令:page, include, taglib:
<%@ 指令名 屬性1="屬性值1" 屬性2="屬性值2" %>
3.表達式: <%=表達式 %>
4.Scriptlet <% Java代碼 %>
5.聲明: <%! %>:變量和方法
6.動作: <jsp:動作名 屬性="屬性值"> </jsp:動作名>
7.注釋:
客戶端看不到的: <%-- --%>
客戶端可以看到的: <!-- -->


Jsp的執行過程:
1.轉譯:Jsp--->Servlet
2.編譯:Servlet---->.class
3.執行:.class
第一次訪問jsp的時候響應速度較慢,后面請求時響應速度快

腳本:
表達式: <%= %>
Scriptlet: <% %>
聲明: <%! %>

指令:
page:language, import, errorPage, isErrorpage
include:file
taglib:uri:指定標簽庫描述符的路徑 prefix:指定標簽的前綴

隱式對象:
分類:
1.輸入和輸出對象:request(HttpServletRequest), 
                 response(HttpServletResponse), 
                 out(JspWriter), servlet中的out是PrintWriter
2.作用域通信對象:pageContext, request, 
                 session(HttpSession),
                 application(ServletContext)
3.Servlet對象:page(this), config
4.錯誤對象:exception
    
JavaBean:
一個標準的JavaBean有三個條件
1.共有的類
2.具有不帶參數的公共的構造方法
3.具有set()和get()方法
4.私有屬性

Jsp中的標準動作:
1.useBean:創建JavaBean的一個實例
<jsp:useBean id="stu" class="com.westaccp.test.Student" scope="page/session/application/request" />
2.setProperty:給JavaBean的屬性賦值
<jsp:setProperty name="stu" property="stuName" value="zhangsan" />
<jsp:setProperty name="stu" property="stuName" param="txtName" />
value和param不能同時使用
偷懶的方法: <jsp:setProperty name="stu" property="*" />
這個時候需要注意的是,表單元素的名字必須和JavaBean的屬性值
一模一樣
3.getProperty:獲得JvaBean的屬性值
<jsp:getProperty name="stu" property="stuName" />
4.forward:內部跳轉,相當于request.getRequestDispatcher().forward(request, response);
<jsp:forward page="index.jsp" />
5.include:包含
<jsp:include page="header.jsp" flush="true" />

表達式語言:
EL: Expression Language
語法格式: ${表達式 }
表示式 = 運算符 + 操作數
運算符:跟Java比較,多了一個empty, 少了一個賦值運算符
${empty ""} : true
${empty null} :true
操作數:
-->常量:布爾型(true/false), 整型, 浮點型, 字符串(可以用'', 還可以用""), Null
-->變量:
    1.指的是放在四個標準范圍里的屬性(page, request, session, application)
    2.在編準范圍內的搜索順序:page-->request--->session--->application
    3.怎么取得變量值:點運算符., 還以用[]
     <% 
      request.setAttribute("name", "lisi");
    %>
    ${requestScope.name}
    或者
    ${requestScope["name"]}
-->隱式對象
    1.pageContext:通過它可以訪問request, session, servletContext
    2.跟范圍由關的:pageScope, requestScope, sessionScope, applicationScope
    3.跟輸入有關的:param, paramValues
    4.其他的:header, cookie, headervalues,

EL表達式適用的場合:
1.可以在靜態文本中使用
2.與自定義標簽結合使用
3.和JavaBean結合使用
<jsp:userBean id="stu" class="com.westaccp.test.Student" scope="session" />
<jsp:setProperty name="stu" property="stuName" value="hello" />
${stu.stuName}

自定義標簽:
1.標簽處理程序實現
--->實現:繼承自BodyTagSupport或者TagSupport
          一般會重寫doStartTag(), doEndTag(), doAfterBody()
--->描述:在標簽庫描述符文件中描述(.tld)
     <taglib>
        <tlib-version>1.0 </tlib-version>
        <jsp-version>2.0 </jsp-version>
        <short-name>simpletag </short-name>
    
        <tag>
         <name>showbody </name>
         <tag-class>com.westaccp.test.ShowBodyTag </tag-class>
         <body-content>empty/jsp </body-content>
         <attribute>
          <name>color </name>
         </attribute>
        </tag>
     </taglib>
--->使用: <%@ taglib uri="WEB-INF/mytag.tld" prefix="my" %>
           <my:showbody />
2.標簽文件
--->實現和描述
     在.tag文件中實現
     設置主體內容: <%@ body-content="empty/scriptless" %>
     設置屬性: <%@ attribute name="name" required="true" rtexprvalue="true" %>
     有主體內容: <jsp:doBody scope="session" var="theBody" />
      <%
        String body = (String) session.getAttribute("theBody");
     %>
--->使用
     WEB-INF/tags/sayhello.tag
      <%@ taglib tagdir="/WEB-INF/tags/" prefix="you" %>
      <you:sayhello />
     
標準標簽庫:
1.核心標簽庫
-->通用:
     set: <c:set var="" value="" scope="" />
     out: <c:out value="" />
     remove:  <c:remove var="" scope="" />
-->條件:
     if: <c:if test="">..... </c:if> 
     choose:  <c:choose>
             <c:when test="">... </c:when>
             <c:when test="">... </c:when>
             <c:when test="">... </c:when>
                .....
                 <c:otherwise>... </otherwise>           
              </c:choose>
-->迭代:
    forEach: <forEach var="" items="" varStatus="" begin="" end="">
    foTokens: <foTodens var="" items="" delim=",; ¦"> </foTodens>
    Java,C#;SQL ¦C
2.I18N與格式化標簽庫
-->setLocale:設置本地區域
-->bundle:設置資源包
-->setBundle:設置資源包
-->message:輸出消息
3.SQL標簽庫
-->setDataSource:設置數據源,用于獲得與數據庫的連接
-->query:執行查詢
-->update:執行增,刪,改
-->transaction:事務
-->param:參數
4.XML標簽庫

過濾器:
生命周期:
1.實例華:
2.初始化:init()
3.過濾:doFilter()
4.銷毀:destroy()
5.不可用

配置:
<filter>
<filter-name> </filter-name>
<filter-class> </filter-class>
</filter>
<filter-mapping>
<filter-name> </filter-name>
<url-pattern> </url-pattern>
</filter-mapping>

幾個重要的接口:
1.Filter:init(), doFilter(), destroy()
2.FilterChain: doFilter(request, response)
3.FilterConfig:getFilterName(), getInitParameter(),

過濾器鏈:--->1--->2--->3--->Servlet 請求
         <----1 <---2 <---3 <---        響應


楊景 2008-04-06 13:50 發表評論
]]>
數據庫查詢優化原則(轉)http://www.aygfsteel.com/java-my-love/articles/190371.html楊景楊景Wed, 02 Apr 2008 06:56:00 GMThttp://www.aygfsteel.com/java-my-love/articles/190371.htmlhttp://www.aygfsteel.com/java-my-love/comments/190371.htmlhttp://www.aygfsteel.com/java-my-love/articles/190371.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/190371.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/190371.html    2.應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
    select id from t where num is null
    可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢:
    select id from t where num=0

    3.應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。

    4.應盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
    select id from t where num=10 or num=20
    可以這樣查詢:
    select id from t where num=10
    union all
    select id from t where num=20

    5.in 和 not in 也要慎用,否則會導致全表掃描,如:
    select id from t where num in(1,2,3)
    對于連續的數值,能用 between 就不要用 in 了:
    select id from t where num between 1 and 3

    6.下面的查詢也將導致全表掃描:
    select id from t where name like '%abc%'
    若要提高效率,可以考慮全文檢索。

    7.如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
    select id from t where num=@num
    可以改為強制查詢使用索引:
    select id from t with(index(索引名)) where num=@num

    8.應盡量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
    select id from t where num/2=100
    應改為:
    select id from t where num=100*2

    9.應盡量避免在where子句中對字段進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:
    select id from t where substring(name,1,3)='abc'--name以abc開頭的id
    select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
    應改為:
    select id from t where name like 'abc%'
    select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'

    10.不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。

    11.在使用索引字段作為條件時,如果該索引是復合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引,否則該索引將不會被使用,并且應盡可能的讓字段順序與索引順序相一致。

    12.不要寫一些沒有意義的查詢,如需要生成一個空表結構:
    select col1,col2 into #t from t where 1=0
    這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
    create table #t(...)

    13.很多時候用 exists 代替 in 是一個好的選擇:
    select num from a where num in(select num from b)
    用下面的語句替換:
    select num from a where exists(select 1 from b where num=a.num)

    14.并不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對查詢效率起不了作用。
 15.索引并不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

    16.應盡可能的避免更新 clustered 索引數據列,因為 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引數據列,那么需要考慮是否應將該索引建為 clustered 索引。

    17.盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連接時會逐個比較字符串中每一個字符,而對于數字型而言只需要比較一次就夠了。

    18.盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長字段存儲空間小,可以節省存儲空間,其次對于查詢來說,在一個相對較小的字段內搜索效率顯然要高些。

    19.任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。

    20.盡量使用表變量來代替臨時表。如果表變量包含大量數據,請注意索引非常有限(只有主鍵索引)。

    21.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。

    22.臨時表并不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對于一次性事件,最好使用導出表。

    23.在新建臨時表時,如果一次性插入數據量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然后insert。

    24.如果使用到了臨時表,在存儲過程的最后務必將所有的臨時表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統表的較長時間鎖定。

    25.盡量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那么就應該考慮改寫。

    26.使用基于游標的方法或臨時表方法之前,應先尋找基于集的解決方案來解決問題,基于集的方法通常更有效。

    27.與臨時表一樣,游標并不是不可使用。對小型數據集使用 FAST_FORWARD 游標通常要優于其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括“合計”的例程通常要比使用游標執行的速度快。如果開發時間允許,基于游標的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。

    28.在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句后向客戶端發送 DONE_IN_PROC 消息。

    29.盡量避免大事務操作,提高系統并發能力。

    30.盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。



楊景 2008-04-02 14:56 發表評論
]]>
網站設計中43個你應當避免的錯誤(轉)http://www.aygfsteel.com/java-my-love/articles/189692.html楊景楊景Sun, 30 Mar 2008 16:23:00 GMThttp://www.aygfsteel.com/java-my-love/articles/189692.htmlhttp://www.aygfsteel.com/java-my-love/comments/189692.htmlhttp://www.aygfsteel.com/java-my-love/articles/189692.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/189692.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/189692.html     2. 讓網站易于速讀。因特網不是書,因此沒必要使用大段的文字。 也許我訪問你的網站時我正在忙于其他工作,我不得不迅速讀完所有內容。 項目符號、標題、副標題、列表,這些都能幫助讀者迅速找到他想要的內容。

    3. 不要使用難于閱讀的花哨字體。當然,某些字體可以讓網站精彩紛呈。 不過它們容易閱讀嗎?如果你的主要目的是傳遞信息并讓讀者閱讀, 你應該讓閱讀過程舒服些。

    4. 不要用小字體。如上一條所述,你得讓讀者閱讀時感到舒服。 雖然我的Firefox有放大功能,但如果必須放大才能看清一個網站的話, 我就再也不會去訪問它了。

    5. 不要打開新瀏覽器窗口。我的第一個網站曾經經常這么做。 原因很簡單,在新窗口中打開外部鏈接,用戶就不必離開我的網站。 錯!讓用戶決定如何打開鏈接,否則瀏覽器上大大的后退按鈕就沒必要存在了。 不用擔心用戶離開你的網站,在必要的時候他們會回來的。

    6. 不要改變用戶的瀏覽器窗口大小。用戶有權控制自己的瀏覽器。 如果你改變窗口大小,你會在他們面前失去信用。

    7. 不必要時不要讓用戶注冊。直白地講,我上網是為了獲取信息,不是為了別的。 不要強迫我注冊并留下我的電子郵件以及其他信息,除非特別必要(比如你 能提供的消息非常有價值)。

    8. 不要在未經訪問者同意的情況下為他們訂閱電子雜志。 不要在訪問者注冊時自動給他們訂閱電子雜志。 不請自來的郵件可不是個交朋友的好辦法。

    9. 不要過多使用Flash。Flash不僅會增加網站的讀取時間, 過度使用甚至會讓訪問者感到不快。只有當靜態頁面無法表達你的意圖時 才使用Flash。

    10. 不要播放音樂。早些年Web開發者都喜歡在網站中集成音樂,結果他們失敗了。 記住,永遠不要使用音樂。

    11. 當你必須使用聲音時,讓用戶啟動它。有時你必須使用聲音文件, 比如你要給用戶發送一份演講,或者你的教程包含聲音。這沒問題,但要讓用戶來控制, 讓用戶點擊“播放”按鈕,別在打開網頁的瞬間播放聲音。

    12. 不要讓標志弄亂你的網站。社交網絡和社區的標志會讓你的網站看起來十分不專業。 就算是獎章和榮譽等標志也應當放到“關于我們”頁面上。

    13. 不要使用“點擊進入”頁面。用戶訪問到內容的步驟越少越好。

    14. 注意要留下聯系方式。最差的莫過于網站沒有留下聯系方式的了。 不僅對訪問者不友好,而且對你也沒好處,你會錯過珍貴的反饋信息。

    15. 不要影響“后退”按鈕的動作。這是網站可用性的最基本的理念。 在任何情況下都不能影響“后退”按鈕的動作。比如,打開新窗口會破壞它, 某些Javas cript鏈接也會破壞它。

    16. 不要用閃爍的文字。除非你的訪問者來自1996年,否則別用閃爍文字。

    17. 避免復雜的URL結構。一個簡單的基于關鍵字的URL結構不僅能提高你的搜索引擎排名, 還能讓訪問者在訪問之前了解網頁內容。

    18. 用CSS布局,不要使用表格。HTML表格曾經被用于頁面布局, 但沒有必要拘泥于此,尤其是在CSS誕生之后。CSS更快、更穩定, 并能提供更多的特性。

    19. 保證用戶可以搜索整個網站。搜索引擎帶來因特網革命的原因,就是 它使得信息查找變得十分容易。別在你的網站上唱反調。

    20. 避免使用下拉菜單。用戶應當直觀地看到所有導航選項。 下拉菜單會造成混亂,并且會隱藏訪問者真正要找的信息。

    21. 使用文字做導航欄。文字導航不僅速度快,而且更穩定。 例如,有些用戶上網時會關閉圖片。

    22. 如果需要鏈接到PDF文檔,一定要注明。你一定有過點擊鏈接之后, 瀏覽器就像死掉一樣等待Acrobat Reader啟動,只為了打開一個(你不想看的)PDF? 這是個不小的麻煩,因此一定要在指向PDF的鏈接旁特別說明,使用戶可以采取相應措施。

    23. 不要用多種版本讓訪問者迷惑。你想用哪種帶寬?56Kbps?128Kbps?Flash版還是HTML版? 嗨,我只想快點看到內容!

    24. 不要在內容中混合廣告。在內容中混合廣告(如Adsense)也許會增加短期內的廣告點擊率, 但從長遠角度來看,這會減少網站的人氣。憤怒的用戶會離開的。

    25. 使用簡單的導航結構。過猶不及。這個規則通常適用于人和選擇上。 確保你的網站的導航結構單純簡潔。你不想讓用戶在查找信息時遇到麻煩吧?

    26. 避免內容介紹。別強迫用戶在訪問到真正內容之前看某些東西。 這很令人憤怒,除非你提供的信息是用戶必須的,否則他不會等下去。

    27. 不要使用FrontPage。這一點也適用于其他廉價的HTML編輯器。 它們讓頁面設計變得更方便,但其輸出結果將會非常低級,不兼容不同的瀏覽器, 并且會包含錯誤。

    28. 保證你的網站兼容大部分瀏覽器。瀏覽器并不完全相同,在解釋CSS和其他 語言的方法也相差甚遠。不管你是否愿意,你應當讓網站兼容市面上的常用瀏覽器, 否則你會永遠地失去部分讀者。

    29. 保證在鏈接上添加有意義的文字。以前我經常犯這個錯誤。告訴人們“點擊這里”很容易, 但這沒有效果。要保證鏈接文字有意義。它使得訪問者知道點擊鏈接之后將出現什么, 也能為鏈接指向的外部站點帶來SEO效果。

    30. 不要在狀態欄中隱藏鏈接。用戶還必須能在狀態欄中看到鏈接指向哪里。 如果你隱藏了鏈接(即使是由于其他原因),那么你也會喪失信譽。

    31. 使鏈接可見。訪問者應能輕易識別出哪些能點擊,哪些不能。 確保鏈接的顏色有強烈的對比(標準的藍色通常是最好的)??赡艿脑挘?nbsp;最好加上下劃線。

    32. 不要在普通文本上添加下劃線或者顏色。除非特別需要,否則不要為普通文字添加下劃線。 就像用戶需要識別哪些能點擊一樣,他們不應當將本不能點擊的文字誤認為能夠點擊。

    33. 改變訪問過的鏈接的顏色。這一點對于提高網站可用性非常重要。 改變訪問過的鏈接顏色有助于用戶在網站中定位,確保他們不會不經意地 訪問同一頁面兩次。

    34. 不要使用動態GIF。除非你有需要動畫的廣告條,否則避免使用動態GIF。 它會使網站看上去很業余,并且會分散訪問者的注意力。

    35. 給圖像添加ALT和TITLE屬性。ALT和TITLE不僅會帶來SEO效果,而且 對盲人有很大幫助。

    36. 不要用令人不快的顏色。如果用戶連續閱讀10分鐘后覺得頭疼, 那么你最好選擇別的配色方案。根據你的目的決定設計(例如,創造一種氛圍 使得用戶將注意力放在網站內容上,等等)。

    37. 不要彈出窗口。這一點涉及任何種類的彈出窗口。即使用戶要求使用, 彈出窗口也不宜使用,因為它會被彈出窗口攔截功能阻攔。

    38. 不要使用Javas cript做鏈接。遠離那些點擊之后執行一小段Javas cript的鏈接, 它們經常給用戶帶來麻煩。

    39. 在頁面底部放置有意義的鏈接。訪問者在找不到所需信息時通常會滾動到頁面最底端。 作為最后的手段,你應當在頁面底部放一個“聯系我們”頁面的鏈接。

    40. 避免網頁過長。如果用戶老是需要滾動才能看到內容,他通常會采取的做法是 跳過它們。如果你的網站正好如此,那么應當縮短內容并優化導航結構。

    41. 禁止使用水平滾動條。雖然垂直滾動條可以接受,但水平滾動條卻遠非如此。 現在的流行分辨率是1024x768,要確保網站能容納在其中。

    42. 禁止出現拼寫或語法錯誤。這不是網站設計的錯,但卻是影響網站整體質量的重要因素。 確保鏈接和文字中沒有拼寫或語法錯誤。

    43. 如果你使用圖片認證,要保證能看清其字符。有些網站將圖片認證作為對抗垃圾評論的方法, 或是在注冊表單上使用。其中有個問題就是,用戶經常需要叫上全家人來討論圖片上到底是什么字母


楊景 2008-03-31 00:23 發表評論
]]>
Hibernate數據加載—Session.get()/load()方法異同http://www.aygfsteel.com/java-my-love/articles/189599.html楊景楊景Sun, 30 Mar 2008 05:41:00 GMThttp://www.aygfsteel.com/java-my-love/articles/189599.htmlhttp://www.aygfsteel.com/java-my-love/comments/189599.htmlhttp://www.aygfsteel.com/java-my-love/articles/189599.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/189599.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/189599.html
如果未能發現符合條件的記錄,get方法返回null,而load方法會拋出一個ObjectNotFoundException。
Load方法可返回實體的代理類實例,而get方法永遠直接返回實體類。
load方法可以充分利用內部緩存和二級緩存中的現有數據,而get方法則僅僅在內部緩存中進行數據查找,如沒有發現對應數據,將越過二級緩存,直接調用SQL完成數據讀取。
Session在加載實體對象時,將經過的過程:

首先,Hibernate中維持了兩級緩存。第一級緩存由Session實例維護,其中保持了Session當前所有關聯實體的數據,也稱為內部緩存。而第二級緩存則存在于SessionFactory層次,由當前所有由本SessionFactory構造的Session實例共享。出于性能考慮,避免無謂的數據庫訪問,Session在調用數據庫查詢功能之前,會先在緩存中進行查詢。首先在第一級緩存中,通過實體類型和id進行查找,如果第一級緩存查找命中,且數據狀態合法,則直接返回。
之后,Session會在當前“NonExists”記錄中進行查找,如果“NonExists”記錄中存在同樣的查詢條件,則返回null。“NonExists”記錄了當前Session實例在之前所有查詢操作中,未能查詢到有效數據的查詢條件(相當于一個查詢黑名單列表)。如此一來,如果Session中一個無效的查詢條件重復出現,即可迅速作出判斷,從而獲得最佳的性能表現。
對于load方法而言,如果內部緩存中未發現有效數據,則查詢第二級緩存,如果第二級緩存命中,則返回。
如在緩存中未發現有效數據,則發起數據庫查詢操作(Select SQL),如經過查詢未發現對應記錄,則將此次查詢的信息在“NonExists”中加以記錄,并返回null。
根據映射配置和Select SQL得到的ResultSet,創建對應的數據對象。
將其數據對象納入當前Session實體管理容器(一級緩存)。
執行Interceptor.onLoad方法(如果有對應的Interceptor)。
將數據對象納入二級緩存。
如果數據對象實現了LifeCycle接口,則調用數據對象的onLoad方法。
返回數據對象。

楊景 2008-03-30 13:41 發表評論
]]>
JAVA的容器---List Map Set http://www.aygfsteel.com/java-my-love/articles/188848.html楊景楊景Wed, 26 Mar 2008 12:18:00 GMThttp://www.aygfsteel.com/java-my-love/articles/188848.htmlhttp://www.aygfsteel.com/java-my-love/comments/188848.htmlhttp://www.aygfsteel.com/java-my-love/articles/188848.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/188848.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/188848.html

JAVA的容器---List,Map,Set
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap

Collection接口
  Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)。一些 Collection允許相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。
  所有實現Collection接口的類都必須提供兩個標準的構造函數:無參數的構造函數用于創建一個空的Collection,有一個 Collection參數的構造函數用于創建一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。后一個構造函數允許用戶復制一個Collection。
  如何遍歷Collection中的每一個元素?不論Collection的實際類型如何,它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子即可逐一訪問Collection中每一個元素。典型的用法如下:
    Iterator it = collection.iterator(); // 獲得一個迭代子
    while(it.hasNext()) {
      Object obj = it.next(); // 得到下一個元素
    }
  由Collection接口派生的兩個接口是List和Set。

List接口
  List是有序的Collection,使用此接口能夠精確的控制每個元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數組下標)來訪問List中的元素,這類似于Java的數組。
和下面要提到的Set不同,List允許有相同的元素。
  除了具有Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個 ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素,還能向前或向后遍歷。
  實現List接口的常用類有LinkedList,ArrayList,Vector和Stack。

LinkedList
  LinkedList實現了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在 LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。
  注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:
    List list = Collections.synchronizedList(new LinkedList(...));

ArrayList
  ArrayList實現了可變大小的數組。它允許所有元素,包括null。ArrayList沒有同步。
size,isEmpty,get,set方法運行時間為常數。但是add方法開銷為分攤的常數,添加n個元素需要O(n)的時間。其他的方法運行時間為線性。
  每個ArrayList實例都有一個容量(Capacity),即用于存儲元素的數組的大小。這個容量可隨著不斷添加新元素而自動增加,但是增長算法并沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。
  和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。

Vector
  Vector非常類似ArrayList,但是Vector是同步的。由Vector創建的Iterator,雖然和ArrayList創建的 Iterator是同一接口,但是,因為Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出ConcurrentModificationException,因此必須捕獲該異常。

Stack
  Stack繼承自Vector,實現一個后進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop 方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。Stack剛創建后是空棧。

Set接口
  Set是一種不包含重復的元素的Collection,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。
  很明顯,Set的構造函數有一個約束條件,傳入的Collection參數不能包含重復的元素。
  請注意:必須小心操作可變對象(Mutable Object)。如果一個Set中的可變元素改變了自身狀態導致Object.equals(Object)=true將導致一些問題。

Map接口
  請注意,Map沒有繼承Collection接口,Map提供key到value的映射。一個Map中不能包含相同的key,每個key只能映射一個 value。Map接口提供3種集合的視圖,Map的內容可以被當作一組key集合,一組value集合,或者一組key-value映射。

Hashtable
  Hashtable繼承Map接口,實現一個key-value映射的哈希表。任何非空(non-null)的對象都可作為key或者value。
  添加數據使用put(key, value),取出數據使用get(key),這兩個基本操作的時間開銷為常數。
Hashtable通過initial capacity和load factor兩個參數調整性能。通常缺省的load factor 0.75較好地實現了時間和空間的均衡。增大load factor可以節省空間但相應的查找時間將增大,這會影響像get和put這樣的操作。
使用Hashtable的簡單示例如下,將1,2,3放到Hashtable中,他們的key分別是”one”,”two”,”three”:
    Hashtable numbers = new Hashtable();
    numbers.put(“one”, new Integer(1));
    numbers.put(“two”, new Integer(2));
    numbers.put(“three”, new Integer(3));
  要取出一個數,比如2,用相應的key:
    Integer n = (Integer)numbers.get(“two”);
    System.out.println(“two = ” + n);
  由于作為key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作為key的對象都必須實現hashCode和equals方法。hashCode和equals方法繼承自根類Object,如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同,如果兩個不同對象的hashCode相同,這種現象稱為沖突,沖突會導致操作哈希表的時間開銷增大,所以盡量定義好的hashCode()方法,能加快哈希表的操作。
  如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時復寫equals方法和hashCode方法,而不要只寫其中一個。
  Hashtable是同步的。

HashMap
  HashMap和Hashtable類似,不同之處在于HashMap是非同步的,并且允許null,即null value和null key。,但是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap 的容量成比例。因此,如果迭代操作的性能相當重要的話,不要將HashMap的初始化容量設得過高,或者load factor過低。

WeakHashMap
  WeakHashMap是一種改進的HashMap,它對key實行“弱引用”,如果一個key不再被外部所引用,那么該key可以被GC回收。

總結
  如果涉及到堆棧,隊列等操作,應該考慮用List,對于需要快速插入,刪除元素,應該使用LinkedList,如果需要快速隨機訪問元素,應該使用ArrayList。
  如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。
  要特別注意對哈希表的操作,作為key的對象要正確復寫equals和hashCode方法。
  盡量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以后需要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程。



楊景 2008-03-26 20:18 發表評論
]]>
為什么要用webservice解理文章(轉載)http://www.aygfsteel.com/java-my-love/articles/188701.html楊景楊景Wed, 26 Mar 2008 04:44:00 GMThttp://www.aygfsteel.com/java-my-love/articles/188701.htmlhttp://www.aygfsteel.com/java-my-love/comments/188701.htmlhttp://www.aygfsteel.com/java-my-love/articles/188701.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/188701.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/188701.html
  實際上,WebService的主要目標是跨平臺的可互操作性。為了達到這一目標,WebService完全基于XML(可擴展標記語言)、XSD(XMLSchema)等獨立于平臺、獨立于軟件供應商的標準,是創建可互操作的、分布式應用程序的新平臺。由此可以看出,在以下三種情況下,使用WebService會帶來極大的好處。

  長項一:跨防火墻的通信

  如果應用程序有成千上萬的用戶,而且分布在世界各地,那么客戶端和服務器之間的通信將是一個棘手的問題。因為客戶端和服務器之間通常會有防火墻或者代理服務器。在這種情況下,使用DCOM就不是那么簡單,通常也不便于把客戶端程序發布到數量如此龐大的每一個用戶手中。傳統的做法是,選擇用瀏覽器作為客戶端,寫下一大堆ASP頁面,把應用程序的中間層暴露給最終用戶。這樣做的結果是開發難度大,程序很難維護。

  圖1通過WebService集成應用程序

  舉個例子,在應用程序里加入一個新頁面,必須先建立好用戶界面(Web頁面),并在這個頁面后面,包含相應商業邏輯的中間層組件,還要再建立至少一個ASP頁面,用來接受用戶輸入的信息,調用中間層組件,把結果格式化為HTML形式,最后還要把“結果頁”送回瀏覽器。要是客戶端代碼不再如此依賴于HTML表單,客戶端的編程就簡單多了。

  如果中間層組件換成WebService的話,就可以從用戶界面直接調用中間層組件,從而省掉建立ASP頁面的那一步。要調用WebService,可以直接使用MicrosoftSOAPToolkit或.NET這樣的SOAP客戶端,也可以使用自己開發的SOAP客戶端,然后把它和應用程序連接起來。不僅縮短了開發周期,還減少了代碼復雜度,并能夠增強應用程序的可維護性。同時,應用程序也不再需要在每次調用中間層組件時,都跳轉到相應的“結果頁”。

  從經驗來看,在一個用戶界面和中間層有較多交互的應用程序中,使用WebService這種結構,可以節省花在用戶界面編程上20%的開發時間。另外,這樣一個由WebService組成的中間層,完全可以在應用程序集成或其它場合下重用。最后,通過WebService把應用程序的邏輯和數據“暴露”出來,還可以讓其它平臺上的客戶重用這些應用程序。

  長項二:應用程序集成

  企業級的應用程序開發者都知道,企業里經常都要把用不同語言寫成的、在不同平臺上運行的各種程序集成起來,而這種集成將花費很大的開發力量。應用程序經常需要從運行在IBM主機上的程序中獲取數據;或者把數據發送到主機或UNIX應用程序中去。即使在同一個平臺上,不同軟件廠商生產的各種軟件也常常需要集成起來。通過WebService,應用程序可以用標準的方法把功能和數據“暴露”出來,供其它應用程序使用。

  例如,有一個訂單登錄程序,用于登錄從客戶來的新訂單,包括客戶信息、發貨地址、數量、價格和付款方式等內容;還有一個訂單執行程序,用于實際貨物發送的管理。這兩個程序來自不同軟件廠商。一份新訂單進來之后,訂單登錄程序需要通知訂單執行程序發送貨物。通過在訂單執行程序上面增加一層WebService,訂單執行程序可以把“AddOrder”函數“暴露”出來。這樣,每當有新訂單到來時,訂單登錄程序就可以調用這個函數來發送貨物了。

  長項三:B2B的集成

  用WebService集成應用程序,可以使公司內部的商務處理更加自動化。但當交易跨越供應商和客戶、突破公司的界限時會怎么樣呢?跨公司的商務交易集成通常叫做B2B集成。

  WebService是B2B集成成功的關鍵。通過WebService,公司可以把關鍵的商務應用“暴露”給指定的供應商和客戶。例如,把電子下單系統和電子發票系統“暴露”出來,客戶就可以以電子的方式發送訂單,供應商則可以以電子的方式發送原料采購發票。當然,這并不是一個新的概念,EDI(電子文檔交換)早就是這樣了。但是,WebService的實現要比EDI簡單得多,而且WebService運行在Internet上,在世界任何地方都可輕易實現,其運行成本就相對較低。不過,WebService并不像EDI那樣,是文檔交換或B2B集成的完整解決方案。WebService只是B2B集成的一個關鍵部分,還需要許多其它的部分才能實現集成。

  用WebService來實現B2B集成的最大好處在于可以輕易實現互操作性。只要把商務邏輯“暴露”出來,成為WebService,就可以讓任何指定的合作伙伴調用這些商務邏輯,而不管他們的系統在什么平臺上運行,使用什么開發語言。這樣就大大減少了花在B2B集成上的時間和成本,讓許多原本無法承受EDI的中小企業也能實現B2B集成。

  長項四:軟件和數據重用

  軟件重用是一個很大的主題,重用的形式很多,重用的程度有大有小。最基本的形式是源代碼模塊或者類一級的重用,另一種形式是二進制形式的組件重用。

  圖2用WebService集成各種應用中的功能,為用戶提供一個統一的界面

  當前,像表格控件或用戶界面控件這樣的可重用軟件組件,在市場上都占有很大的份額。但這類軟件的重用有一個很大的限制,就是重用僅限于代碼,數據不能重用。原因在于,發布組件甚至源代碼都比較容易,但要發布數據就沒那么容易,除非是不會經常變化的靜態數據。

  WebService在允許重用代碼的同時,可以重用代碼背后的數據。使用WebService,再也不必像以前那樣,要先從第三方購買、安裝軟件組件,再從應用程序中調用這些組件;只需要直接調用遠端的WebService就可以了。舉個例子,要在應用程序中確認用戶輸入的地址,只需把這個地址直接發送給相應的WebService,這個WebService就會幫你查閱街道地址、城市、省區和郵政編碼等信息,確認這個地址是否在相應的郵政編碼區域。WebService的提供商可以按時間或使用次數來對這項服務進行收費。這樣的服務要通過組件重用來實現是不可能的,那樣的話你必須下載并安裝好包含街道地址、城市、省區和郵政編碼等信息的數據庫,而且這個數據庫還是不能實時更新的。

  另一種軟件重用的情況是,把好幾個應用程序的功能集成起來。例如,要建立一個局域網上的門戶站點應用,讓用戶既可以查詢聯邦快遞包裹,查看股市行情,又可以管理自己的日程安排,還可以在線購買電影票。現在Web上有很多應用程序供應商,都在其應用中實現了這些功能。一旦他們把這些功能都通過WebService“暴露”出來,就可以非常容易地把所有這些功能都集成到你的門戶站點中,為用戶提供一個統一的、友好的界面。

  將來,許多應用程序都會利用WebService,把當前基于組件的應用程序結構擴展為組件/WebService的混合結構,可以在應用程序中使用第三方的WebService提供的功能,也可以把自己的應用程序功能通過WebService提供給別人。兩種情況下,都可以重用代碼和代碼背后的數據。

  從以上論述可以看出,WebService在通過Web進行互操作或遠程調用的時候是最有用的。不過,也有一些情況,WebService根本不能帶來任何好處。

  短處一:單機應用程序

  目前,企業和個人還使用著很多桌面應用程序。其中一些只需要與本機上的其它程序通信。在這種情況下,最好就不要用WebService,只要用本地的API就可以了。COM非常適合于在這種情況下工作,因為它既小又快。運行在同一臺服務器上的服務器軟件也是這樣。最好直接用COM或其它本地的API來進行應用程序間的調用。當然WebService也能用在這些場合,但那樣不僅消耗太大,而且不會帶來任何好處。

  短處二:局域網的同構應用程序

  在許多應用中,所有的程序都是用VB或VC開發的,都在Windows平臺下使用COM,都運行在同一個局域網上。例如,有兩個服務器應用程序需要相互通信,或者有一個Win32或WinForm的客戶程序要連接局域網上另一個服務器的程序。在這些程序里,使用DCOM會比SOAP/HTTP有效得多。與此相類似,如果一個.NET程序要連接到局域網上的另一個.NET程序,應該使用.NETremoting。有趣的是,在.NETremoting中,也可以指定使用SOAP/HTTP來進行WebService調用。不過最好還是直接通過TCP進行RPC調用,那樣會有效得多。

  總之,只要從應用程序結構的角度看,有別的方法比WebService更有效、更可行,那就不要用WebService。


楊景 2008-03-26 12:44 發表評論
]]>
Struts+Hibernate通用分頁http://www.aygfsteel.com/java-my-love/articles/188355.html楊景楊景Mon, 24 Mar 2008 13:36:00 GMThttp://www.aygfsteel.com/java-my-love/articles/188355.htmlhttp://www.aygfsteel.com/java-my-love/comments/188355.htmlhttp://www.aygfsteel.com/java-my-love/articles/188355.html#Feedback0http://www.aygfsteel.com/java-my-love/comments/commentRss/188355.htmlhttp://www.aygfsteel.com/java-my-love/services/trackbacks/188355.html閱讀全文

楊景 2008-03-24 21:36 發表評論
]]>
主站蜘蛛池模板: 阿克苏市| 嫩江县| 福海县| 武川县| 蒲城县| 万安县| 遵化市| 平顶山市| 广宗县| 汝阳县| 玛纳斯县| 泰顺县| 当雄县| 甘德县| 尚义县| 绍兴县| 海宁市| 襄垣县| 泽库县| 潞城市| 昌图县| 江永县| 泰州市| 资中县| 崇仁县| 名山县| 靖安县| 涟水县| 沙田区| 台东县| 镇雄县| 南岸区| 北安市| 始兴县| 济南市| 东城区| 抚州市| 武城县| 茌平县| 蓬莱市| 岳西县|