<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Java Votary

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      48 隨筆 :: 1 文章 :: 80 評論 :: 0 Trackbacks

    2005年12月26日 #

    ThreadLocal是什么

    早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal為解決多線程程序的并發(fā)問題提供了一種新的思路。使用這個(gè)工具類可以很簡潔地編寫出優(yōu)美的多線程程序。

    ThreadLocal很容易讓人望文生義,想當(dāng)然地認(rèn)為是一個(gè)“本地線程”。其實(shí),ThreadLocal并不是一個(gè)Thread,而是Thread的局部變量,也許把它命名為ThreadLocalVariable更容易讓人理解一些。

    當(dāng)使用ThreadLocal維護(hù)變量時(shí),ThreadLocal為每個(gè)使用該變量的線程提供獨(dú)立的變量副本,所以每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會影響其它線程所對應(yīng)的副本。

    從線程的角度看,目標(biāo)變量就象是線程的本地變量,這也是類名中“Local”所要表達(dá)的意思。

    線程局部變量并不是Java的新發(fā)明,很多語言(如IBM IBM XL FORTRAN)在語法層面就提供線程局部變量。在Java中沒有提供在語言級支持,而是變相地通過ThreadLocal的類提供支持。

    所以,在Java中編寫線程局部變量的代碼相對來說要笨拙一些,因此造成線程局部變量沒有在Java開發(fā)者中得到很好的普及。

    ThreadLocal的接口方法

    ThreadLocal類接口很簡單,只有4個(gè)方法,我們先來了解一下:

    • void set(Object value)

    設(shè)置當(dāng)前線程的線程局部變量的值。

    • public Object get()

    該方法返回當(dāng)前線程所對應(yīng)的線程局部變量。

    • public void remove()

    將當(dāng)前線程局部變量的值刪除,目的是為了減少內(nèi)存的占用,該方法是JDK 5.0新增的方法。需要指出的是,當(dāng)線程結(jié)束后,對應(yīng)該線程的局部變量將自動被垃圾回收,所以顯式調(diào)用該方法清除線程的局部變量并不是必須的操作,但它可以加快內(nèi)存回收的速度。

    • protected Object initialValue()

    返回該線程局部變量的初始值,該方法是一個(gè)protected的方法,顯然是為了讓子類覆蓋而設(shè)計(jì)的。這個(gè)方法是一個(gè)延遲調(diào)用方法,在線程第1次調(diào)用get()或set(Object)時(shí)才執(zhí)行,并且僅執(zhí)行1次。ThreadLocal中的缺省實(shí)現(xiàn)直接返回一個(gè)null。

    值得一提的是,在JDK5.0中,ThreadLocal已經(jīng)支持泛型,該類的類名已經(jīng)變?yōu)門hreadLocal<T>。API方法 也相應(yīng)進(jìn)行了調(diào)整,新版本的API方法分別是void set(T value)、T get()以及T initialValue()。

    ThreadLocal是如何做到為每一個(gè)線程維護(hù)變量的副本的呢?其實(shí)實(shí)現(xiàn)的思路很簡單:在ThreadLocal類中有一個(gè)Map,用于存儲每一個(gè)線程的變量副本,Map中元素的鍵為線程對象,而值對應(yīng)線程的變量副本。我們自己就可以提供一個(gè)簡單的實(shí)現(xiàn)版本:

    代碼清單1 SimpleThreadLocal

    public class SimpleThreadLocal {

    private Map valueMap = Collections.synchronizedMap(new HashMap());

    public void set(Object newValue) {

    valueMap.put(Thread.currentThread(), newValue);①鍵為線程對象,值為本線程的變量副本

    }

    public Object get() {

    Thread currentThread = Thread.currentThread();

    Object o = valueMap.get(currentThread);②返回本線程對應(yīng)的變量

    if (o == null && !valueMap.containsKey(currentThread)) {③如果在Map中不存在,放到Map

    中保存起來。

    o = initialValue();

    valueMap.put(currentThread, o);

    }

    return o;

    }

    public void remove() {

    valueMap.remove(Thread.currentThread());

    }

    public Object initialValue() {

    return null;

    }

    }

    雖然代碼清單9?3這個(gè)ThreadLocal實(shí)現(xiàn)版本顯得比較幼稚,但它和JDK所提供的ThreadLocal類在實(shí)現(xiàn)思路上是相近的。

    一個(gè)TheadLocal實(shí)例

    下面,我們通過一個(gè)具體的實(shí)例了解一下ThreadLocal的具體使用方法。

    代碼清單2 SequenceNumber

    package com.baobaotao.basic;

    public class SequenceNumber {

    通過匿名內(nèi)部類覆蓋ThreadLocalinitialValue()方法,指定初始值

    private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){

    public Integer initialValue(){

    return 0;

    }

    };

    獲取下一個(gè)序列值

    public int getNextNum(){

    seqNum.set(seqNum.get()+1);

    return seqNum.get();

    }

    public static void main(String[] args)

    {

    SequenceNumber sn = new SequenceNumber();

    3個(gè)線程共享sn,各自產(chǎn)生序列號

    TestClient t1 = new TestClient(sn);

    TestClient t2 = new TestClient(sn);

    TestClient t3 = new TestClient(sn);

    t1.start();

    t2.start();

    t3.start();

    }

    private static class TestClient extends Thread

    {

    private SequenceNumber sn;

    public TestClient(SequenceNumber sn) {

    this.sn = sn;

    }

    public void run()

    {

    for (int i = 0; i < 3; i++) {④每個(gè)線程打出3個(gè)序列值

    System.out.println("thread["+Thread.currentThread().getName()+

    "] sn["+sn.getNextNum()+"]");

    }

    }

    }

    }

     

    通常我們通過匿名內(nèi)部類的方式定義ThreadLocal的子類,提供初始的變量值,如例子中①處所示。TestClient線程產(chǎn)生一組序列號, 在③處,我們生成3個(gè)TestClient,它們共享同一個(gè)SequenceNumber實(shí)例。運(yùn)行以上代碼,在控制臺上輸出以下的結(jié)果:

    thread[Thread-2] sn[1]

    thread[Thread-0] sn[1]

    thread[Thread-1] sn[1]

    thread[Thread-2] sn[2]

    thread[Thread-0] sn[2]

    thread[Thread-1] sn[2]

    thread[Thread-2] sn[3]

    thread[Thread-0] sn[3]

    thread[Thread-1] sn[3]

    考察輸出的結(jié)果信息,我們發(fā)現(xiàn)每個(gè)線程所產(chǎn)生的序號雖然都共享同一個(gè)SequenceNumber實(shí)例,但它們并沒有發(fā)生相互干擾的情況,而是各自產(chǎn)生獨(dú)立的序列號,這是因?yàn)槲覀兺ㄟ^ThreadLocal為每一個(gè)線程提供了單獨(dú)的副本。

    Thread同步機(jī)制的比較

    ThreadLocal和線程同步機(jī)制相比有什么優(yōu)勢呢?ThreadLocal和線程同步機(jī)制都是為了解決多線程中相同變量的訪問沖突問題。

    在同步機(jī)制中,通過對象的鎖機(jī)制保證同一時(shí)間只有一個(gè)線程訪問變量。這時(shí)該變量是多個(gè)線程共享的,使用同步機(jī)制要求程序慎密地分析什么時(shí)候?qū)ψ兞窟M(jìn)行讀寫,什么時(shí)候需要鎖定某個(gè)對象,什么時(shí)候釋放對象鎖等繁雜的問題,程序設(shè)計(jì)和編寫難度相對較大。

    而ThreadLocal則從另一個(gè)角度來解決多線程的并發(fā)訪問。ThreadLocal會為每一個(gè)線程提供一個(gè)獨(dú)立的變量副本,從而隔離了多個(gè)線 程對數(shù)據(jù)的訪問沖突。因?yàn)槊恳粋€(gè)線程都擁有自己的變量副本,從而也就沒有必要對該變量進(jìn)行同步了。ThreadLocal提供了線程安全的共享對象,在編 寫多線程代碼時(shí),可以把不安全的變量封裝進(jìn)ThreadLocal。

    由于ThreadLocal中可以持有任何類型的對象,低版本JDK所提供的get()返回的是Object對象,需要強(qiáng)制類型轉(zhuǎn)換。但JDK 5.0通過泛型很好的解決了這個(gè)問題,在一定程度地簡化ThreadLocal的使用,代碼清單 9 2就使用了JDK 5.0新的ThreadLocal<T>版本。

    概括起來說,對于多線程資源共享的問題,同步機(jī)制采用了“以時(shí)間換空間”的方式,而ThreadLocal采用了“以空間換時(shí)間”的方式。前者僅提供一份變量,讓不同的線程排隊(duì)訪問,而后者為每一個(gè)線程都提供了一份變量,因此可以同時(shí)訪問而互不影響。

    Spring使用ThreadLocal解決線程安全問題

    我們知道在一般情況下,只有無狀態(tài)的Bean才可以在多線程環(huán)境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用 域。就是因?yàn)镾pring對一些Bean(如RequestContextHolder、 TransactionSynchronizationManager、LocaleContextHolder等)中非線程安全狀態(tài)采用 ThreadLocal進(jìn)行處理,讓它們也成為線程安全的狀態(tài),因?yàn)橛袪顟B(tài)的Bean就可以在多線程中共享了。

    一般的Web應(yīng)用劃分為展現(xiàn)層、服務(wù)層和持久層三個(gè)層次,在不同的層中編寫對應(yīng)的邏輯,下層通過接口向上層開放功能調(diào)用。在一般情況下,從接收請求到返回響應(yīng)所經(jīng)過的所有程序調(diào)用都同屬于一個(gè)線程,如圖9?2所示:

    通通透透理解ThreadLocal

    1同一線程貫通三層

    這樣你就可以根據(jù)需要,將一些非線程安全的變量以ThreadLocal存放,在同一次請求響應(yīng)的調(diào)用線程中,所有關(guān)聯(lián)的對象引用到的都是同一個(gè)變量。

    下面的實(shí)例能夠體現(xiàn)Spring對有狀態(tài)Bean的改造思路:

    代碼清單3 TopicDao:非線程安全

    public class TopicDao {

    private Connection conn;一個(gè)非線程安全的變量

    public void addTopic(){

    Statement stat = conn.createStatement();引用非線程安全變量

    }

    }

    由于①處的conn是成員變量,因?yàn)閍ddTopic()方法是非線程安全的,必須在使用時(shí)創(chuàng)建一個(gè)新TopicDao實(shí)例(非singleton)。下面使用ThreadLocal對conn這個(gè)非線程安全的“狀態(tài)”進(jìn)行改造:

    代碼清單4 TopicDao:線程安全

    import java.sql.Connection;

    import java.sql.Statement;

    public class TopicDao {

    ①使用ThreadLocal保存Connection變量

    private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();

    public static Connection getConnection(){

    ②如果connThreadLocal沒有本線程對應(yīng)的Connection創(chuàng)建一個(gè)新的Connection,

    并將其保存到線程本地變量中。

    if (connThreadLocal.get() == null) {

    Connection conn = ConnectionManager.getConnection();

    connThreadLocal.set(conn);

    return conn;

    }else{

    return connThreadLocal.get();③直接返回線程本地變量

    }

    }

    public void addTopic() {

    ④從ThreadLocal中獲取線程對應(yīng)的Connection

    Statement stat = getConnection().createStatement();

    }

    }

    不同的線程在使用TopicDao時(shí),先判斷connThreadLocal.get()是否是null,如果是null,則說明當(dāng)前線程還沒有對 應(yīng)的Connection對象,這時(shí)創(chuàng)建一個(gè)Connection對象并添加到本地線程變量中;如果不為null,則說明當(dāng)前的線程已經(jīng)擁有了 Connection對象,直接使用就可以了。這樣,就保證了不同的線程使用線程相關(guān)的Connection,而不會使用其它線程的 Connection。因此,這個(gè)TopicDao就可以做到singleton共享了。

    當(dāng)然,這個(gè)例子本身很粗糙,將Connection的ThreadLocal直接放在DAO只能做到本DAO的多個(gè)方法共享Connection時(shí) 不發(fā)生線程安全問題,但無法和其它DAO共用同一個(gè)Connection,要做到同一事務(wù)多DAO共享同一Connection,必須在一個(gè)共同的外部類 使用ThreadLocal保存Connection。

    小結(jié)

    ThreadLocal是解決線程安全問題一個(gè)很好的思路,它通過為每個(gè)線程提供一個(gè)獨(dú)立的變量副本解決了變量并發(fā)訪問的沖突問題。在很多情況 下,ThreadLocal比直接使用synchronized同步機(jī)制解決線程安全問題更簡單,更方便,且結(jié)果程序擁有更高的并發(fā)性。

    posted @ 2009-07-01 12:15 Dion 閱讀(344) | 評論 (0)編輯 收藏

         摘要: 題記世界是事實(shí)的總體,而不是事物的總體。世界為諸事實(shí)所規(guī)定,為它們既是全部事實(shí)所規(guī)定。——路德維希·維特根斯坦,《邏輯哲學(xué)論》The answer, please?"請回答我..."The stern voice startles you. 一個(gè)嚴(yán)厲的聲音把你嚇個(gè)半死.You were dozing in Mrs. Rosencrantz's high school math class agai...  閱讀全文
    posted @ 2006-03-11 10:02 Dion 閱讀(2111) | 評論 (0)編輯 收藏

    前幾天跟著寫了一個(gè)簡單的例子.
    覺得Drools的配置也沒有什么.
    今天在運(yùn)行house的例子的時(shí)候, 無論怎么樣, 總是異常: 沒有定義的SMF.
    顯然沒有找到我定義的drools.config文件.
    官方網(wǎng)站上是這樣寫地:
    String droolsConfigProp = System.getProperty( "drools.conf" );

    if ( droolsConfigProp != null )
    {
        loadConfig( droolsConfigProp );
    }

    ClassLoader cl = Thread.currentThread( ).getContextClassLoader( ); if ( cl == null )
    {
        cl = getClass( ).getClassLoader( );
    }

    Enumeration configUrls = cl.getResources( "META-INF/drools.conf" );

    if ( !configUrls.hasMoreElements( ) )
    {
        cl = getClass( ).getClassLoader( );
        configUrls = cl.getResources( "META-INF/drools.conf" );
    }

    if ( !configUrls.hasMoreElements( ) )
    {
        cl = ClassLoader.getSystemClassLoader( );
        configUrls = cl.getResources( "META-INF/drools.conf" );
    }

    this.classLoader = cl;
    while ( configUrls.hasMoreElements( ) )
    {
        URL configUrl = (URL) configUrls.nextElement( );
        loadConfig( configUrl );
    }

    好像每一個(gè)旮旯里面都找了, 為什么沒有找到我的呢?
    System.getProperty指向的位置并不一定和loadFromUrl位置一樣.呵呵.
    posted @ 2006-03-11 10:00 Dion 閱讀(1640) | 評論 (0)編輯 收藏

    內(nèi)容提要
           在本文的第一部分,我將討論規(guī)則引擎如何幫助你從軟件的應(yīng)用邏輯中分離出商業(yè)規(guī)則邏輯,以實(shí)現(xiàn)商業(yè)應(yīng)用的靈活性。另外,我還將介紹JSR-94規(guī)則引擎 API,及其開源實(shí)現(xiàn)Drools項(xiàng)目,它是這一新技術(shù)的先驅(qū)。在第二部分,我們將介紹一個(gè)規(guī)則引擎例子,并深入地研究Drools引擎及其JSR-94 擴(kuò)展的復(fù)雜性。

    為什么使用規(guī)則引擎
           商業(yè)世界充滿了關(guān)于變化的陳詞濫調(diào),如任何事物都會改變,唯一不變的是變化等等。而在技術(shù)領(lǐng)域里,情況正好相反。我們?nèi)匀辉谠噲D解決30年前軟件業(yè)中同樣 的一堆問題--也許比30年前還要多的問題。在過去的十年,IT從業(yè)人員淹沒在軟件方法學(xué)的大量文獻(xiàn)中,如快速軟件開發(fā),極限編程,敏捷軟件開發(fā)等,它們 無一例外地強(qiáng)調(diào)靈活和變化的重要性。
           但商業(yè)通常比開發(fā)團(tuán)隊(duì)所依賴的軟件過程和技術(shù)改變得更加迅速。當(dāng)商業(yè)策劃人員試圖重整IT部門,以支持新的業(yè)務(wù)轉(zhuǎn)型時(shí),仍然覺得很費(fèi)勁。

    Lost in Translation
           雖然IT團(tuán)隊(duì)反應(yīng)迅速,但他們通常帶來"電話效應(yīng)"――IT給商業(yè)計(jì)劃的執(zhí)行帶來的阻力和它帶來的利益一樣多。不幸的是,在開發(fā)團(tuán)隊(duì)完全理解商業(yè)決策規(guī)則 并實(shí)現(xiàn)之前,規(guī)則已經(jīng)改變了。在軟件進(jìn)入市場前,它已經(jīng)過時(shí)了,需要進(jìn)行重構(gòu)以滿足新的業(yè)務(wù)需求。如果你是一個(gè)開發(fā)人員,你會知道我在說什么。再也沒有比 在需求變動的情況下構(gòu)造軟件讓開發(fā)人員更沮喪的事情了。作為軟件開發(fā)人員,你必須比業(yè)務(wù)人員更了解業(yè)務(wù),有時(shí)還要了解更多。
           試想一下你是一位商業(yè)決策者。假如公司的成功依賴于你對于市場趨勢敏銳的洞察力,它常常幫助你領(lǐng)先于競爭者利用變化的市場環(huán)境獲利。每天你都會得到更多更 好的市場信息,但并不要緊。完成新產(chǎn)品開發(fā)可能需要6-9個(gè)月,在此期間,對于市場大膽和敏銳的洞察和信息優(yōu)勢可能已經(jīng)浪費(fèi)了。而且,當(dāng)產(chǎn)品發(fā)布時(shí),有這 樣幾種可能:產(chǎn)品沒有什么吸引人的特性,預(yù)算超支,過了產(chǎn)品的最佳發(fā)布期限,或三者兼而有之。
           情況可能還會更糟,在完成產(chǎn)品開發(fā)時(shí),市場環(huán)境和規(guī)劃產(chǎn)品開發(fā)時(shí)相比,已經(jīng)發(fā)生了根本變化。現(xiàn)在你必須要遵守新的規(guī)則,你已經(jīng)喪失了你的邊際優(yōu)勢,而且設(shè) 計(jì)軟件的五人中的三人已經(jīng)離開了公司。你必須給接手的新人重新講解復(fù)雜的業(yè)務(wù)。如果事情不順利,你可能發(fā)現(xiàn)自己要對付一個(gè)缺少文檔,并且你完全不了解的遺 留應(yīng)用。
           你的戰(zhàn)略在哪出現(xiàn)了問題?你在哪里應(yīng)該可以做到更好?最近的輕量級軟件過程,如極限編程,敏捷軟件開發(fā)等都在強(qiáng)調(diào)自動單元測試和軟件功能優(yōu)先級的重要性。 除此之外,還有其他的原則,你的開發(fā)團(tuán)隊(duì)可能也很熟悉,這些原則可以幫助他們對需求的變動作出迅速反應(yīng)并縮短項(xiàng)目的開發(fā)周期。這些原則的大多數(shù),如系統(tǒng)分 解,多年前就已經(jīng)出現(xiàn),并得到了Java平臺的支持(如JMX等),還有如面向?qū)ο蠛徒巧#呀?jīng)內(nèi)建在Java語言中。
           但Java仍然是一門相當(dāng)年輕的語言,而且Java平臺遠(yuǎn)遠(yuǎn)還沒有完備。當(dāng)前在Java社區(qū),一個(gè)引人注目的新技術(shù)是,分離商業(yè)決策者的商業(yè)決策邏輯和應(yīng) 用開發(fā)者的技術(shù)決策,并把這些商業(yè)決策放在中心數(shù)據(jù)庫,讓它們能在運(yùn)行時(shí)(即商務(wù)時(shí)間)可以動態(tài)地管理和修改。這是一個(gè)你值得考慮的策略。
           為什么你的開發(fā)團(tuán)隊(duì)不得不象商業(yè)經(jīng)理人一樣,在代碼中包含復(fù)雜微妙的商業(yè)決策邏輯呢?你怎樣才能向他們解釋決策推理的微妙之處呢?你這樣做是否謹(jǐn)慎呢?可 能不是。象bottom line一樣,某些東西在解釋的過程中丟失了。為什么要冒這樣的風(fēng)險(xiǎn),讓應(yīng)用代碼或測試代碼錯(cuò)誤地表達(dá)你的商業(yè)決策邏輯呢?如果這樣做的話,你怎樣檢查它 們的正確性呢――難道你自己想學(xué)習(xí)如何編程和編寫測試代碼,或者你的客戶會為你測試軟件?你一方面要應(yīng)付市場,一方面要應(yīng)付軟件代碼,這實(shí)在太困難了。
           如果能將這些商業(yè)決策規(guī)則集中地放在一個(gè)地方,以一種你可以理解的格式定義,讓你可以直接管理,而不是散落在代碼的各個(gè)角落,那該有多好。如果你能把商業(yè) 決策規(guī)則獨(dú)立于你的軟件代碼,讓開發(fā)團(tuán)隊(duì)作出技術(shù)決策,你將會獲得更多好處。你的項(xiàng)目開發(fā)周期會更短,軟件對于變動的需求更靈活。

    規(guī)則引擎標(biāo)準(zhǔn)Java API
           2003年11月,Java社區(qū)通過了Java Rule Engine API規(guī)范(JSR-94)的最后草案。這個(gè)新的API讓開發(fā)人員在運(yùn)行時(shí)訪問和執(zhí)行規(guī)則有了統(tǒng)一的標(biāo)準(zhǔn)方式。隨著新規(guī)范產(chǎn)品實(shí)現(xiàn)的成熟和推向市場,開發(fā) 團(tuán)隊(duì)將可以從應(yīng)用代碼中抽取出商業(yè)決策邏輯。
           這就需要新一代的管理工具,幫助商務(wù)經(jīng)理人可以定義和細(xì)化軟件系統(tǒng)的行為。不必通過開發(fā)過程來修改應(yīng)用,并假定可以得到正確的結(jié)果,經(jīng)理人將可以隨時(shí)根據(jù)需要修改決策規(guī)則,并進(jìn)行測試。
           但這將需要開發(fā)人員在設(shè)計(jì)系統(tǒng)時(shí)作出某些改變,并可以得到合適的開發(fā)工具。

    分離商務(wù)和技術(shù)的關(guān)注點(diǎn)
           這是一個(gè)非常簡單的例子,從經(jīng)理人的角度,說明如何分離商務(wù)和技術(shù)的關(guān)注點(diǎn)。
           你管理著一個(gè)反向投資基金。你公司計(jì)算機(jī)系統(tǒng)的一部分用于分析股票價(jià)格,收益和每股凈資產(chǎn),并在需要時(shí)向你提出預(yù)警。這個(gè)計(jì)算機(jī)系統(tǒng)的工作是,識別出PE比率比市場平均值低的股票,并標(biāo)記出來以便進(jìn)一步的檢查。
           你的IT部門擁有一大堆數(shù)據(jù),并開發(fā)了一系列你可以在規(guī)則中引用的簡單數(shù)據(jù)對象。現(xiàn)在,為簡單起見,假設(shè)你是一名受過良好教育的,了解技術(shù)的管理人,你了解XML的基本知識,可以讓你編寫和修改簡單的XML規(guī)則文件。
           你的第一個(gè)規(guī)則是,給道瓊斯所有的股票估值,并剔除P/E比率大于10的股票(這有點(diǎn)過分簡化,但這里只作為一個(gè)例子)。保留下來的股票用來生產(chǎn)一系列報(bào)表。對于這個(gè)簡單的例子,你的規(guī)則文件看起來如下(我們將會過頭來討論這個(gè)文件的結(jié)構(gòu)):

    <stock:overvalued>
        <stock:index> DJIA </stock:index>
        <stock:pe> over 10.0 </stock:pe>
    </stock:overvalued>

           一個(gè)月后,你接到一家巴西分析師公司的電話,雇傭你的公司生成一系列巴西股市的報(bào)表,但他們有更嚴(yán)格的標(biāo)準(zhǔn)。而目前在巴西,P/E比率市場平均值是個(gè)位 數(shù),因此你用來評估被市場低股票的閾值需要改變。除了較低的P/E比率,你的新客戶還要求以Price-to-Book比率作為參考標(biāo)準(zhǔn)。
           你啟動規(guī)則編輯器,并修改規(guī)則以匹配新的評估條件。現(xiàn)在,規(guī)則引擎剔除巴西股市中P/E比率大于6.5,以及Price to Book 比率小于等于1的股票。完成規(guī)則文件修改后,看起來如下:

    <stock:overvalued>
        <stock:index> Brazil </stock:index>
        <stock:pe> over 6.5 </stock:pe>
        <stock:pb> over 1.0 </stock:pb>
    </stock:overvalued>

           你無需為此向開發(fā)團(tuán)隊(duì)作任何解釋。你無需等待他們開發(fā)或測試程序。如果你的規(guī)則引擎的語義足夠強(qiáng)大,讓你描述工作數(shù)據(jù),你可以隨時(shí)按需修改商業(yè)規(guī)則。
           如果限制因素是規(guī)則的定義語言和數(shù)據(jù)模型,你可以確信這兩者將會標(biāo)準(zhǔn)化,并出現(xiàn)先進(jìn)的編輯器和工具,以簡化規(guī)則的定義,保存和維護(hù)。
           現(xiàn)在,我希望你已經(jīng)清楚以下的原則:在這個(gè)例子中,哪只股票是否被選擇是一個(gè)商務(wù)決策,而不是技術(shù)決策。決定將哪只股票交給你的分析師是經(jīng)理人的邏輯 ――"logic of the bottom line"。經(jīng)理人作出這些決策,并可以按需定制應(yīng)用。這些規(guī)則因此變成了一種控制界面,一種新的商業(yè)系統(tǒng)用戶界面。

    使用Rule開發(fā)
           如果在這個(gè)應(yīng)用場景中,你是一個(gè)開發(fā)人員,你的工作會稍微輕松一些。一旦你擁有了一種用于分析股票的規(guī)則語言,你可以取出數(shù)據(jù)對象并交給規(guī)則引擎執(zhí)行。我們將會到規(guī)則語言的討論,但現(xiàn)在我們繼續(xù)剛才的例子。
           你的系統(tǒng)將一系列的stock bean輸入規(guī)則引擎。當(dāng)規(guī)則執(zhí)行后,你可以選出符合條件的股票并可以對它們作進(jìn)一步處理。也許是把它們輸入報(bào)表生成系統(tǒng)。分析師使用這些報(bào)表幫助他們分 析股市。同時(shí),老板也可能讓你使用新的技術(shù)分析工具,并用Dow理論預(yù)測股市的底部和頂部。
           規(guī)則引擎可以讓你的系統(tǒng)變得更簡單,因?yàn)槟銦o需在代碼中編寫商務(wù)邏輯,如怎樣選擇股票,選擇股票過程中奇怪的條件組合等。這些邏輯不再進(jìn)入你的代碼。你將可以專注于數(shù)據(jù)模型。
           現(xiàn)在可以這么認(rèn)為,通過從應(yīng)用代碼中剝離出易變的商業(yè)邏輯,你的效率會更高。但凡是總有例外――簡單應(yīng)用可能并不能從規(guī)則系統(tǒng)中獲益。但如果你開發(fā)一個(gè)大型系統(tǒng),有很多易變的商業(yè)邏輯,你可以考慮在應(yīng)用中集成規(guī)則引擎。
           除了從應(yīng)用代碼中剝離出商業(yè)決策邏輯外,規(guī)則引擎還有其他用處。有時(shí)候你需要應(yīng)用成百上千的規(guī)則進(jìn)行決策,并且有上千個(gè)對象和這些規(guī)則一起使用。很難想象 有什么先進(jìn)的人工智能引擎可以處理這種情況。遇到這種情況,你需要一個(gè)極快的決策算法或是大型機(jī)。大型機(jī)并不便宜,但你可以非常便宜的得到效率和可伸縮性 最好的算法。

    Bob McWhirter的Drools項(xiàng)目
           現(xiàn)在,我要介紹Drools項(xiàng)目,Charles Forgy Rete算法的一個(gè)增強(qiáng)的Java語言實(shí)現(xiàn)。Drools是一個(gè)Bob McWhirter開發(fā)的開源項(xiàng)目,放在The Codehaus上。在我寫這篇文章時(shí),Drools發(fā)表了2.0-beata-14版。在CVS中,已完整地實(shí)現(xiàn)了JSR94 Rule Engine API并提供了單元測試代碼。
           Rete算法是Charles Forgy在1979年發(fā)明的,是目前用于生產(chǎn)系統(tǒng)的效率最高的算法(除了私有的Rete II)。Rete是唯一的,效率與執(zhí)行規(guī)則數(shù)目無關(guān)的決策支持算法。For the uninitiated, that means it can scale to incorporate and execute hundreds of thousands of rules in a manner which is an order of magnitude more efficient then the next best algorithm。Rete應(yīng)用于生產(chǎn)系統(tǒng)已經(jīng)有很多年了,但在Java開源軟件中并沒有得到廣泛應(yīng)用(討論Rete算法的文檔參見http://herzberg.ca.sandia.gov/jess/docs/61/rete.html。)。
           除了應(yīng)用了Rete核心算法,開源軟件License和100%的Java實(shí)現(xiàn)之外,Drools還提供了很多有用的特性。其中包括實(shí)現(xiàn)了JSR94 API和創(chuàng)新的規(guī)則語義系統(tǒng),這個(gè)語義系統(tǒng)可用來編寫描述規(guī)則的語言。目前,Drools提供了三種語義模塊――Python模塊,Java模塊和 Groovy模塊。本文余下部分集中討論JSR94 API,我將在第二篇文章中討論語義系統(tǒng)。
           作為使用javax.rules API的開發(fā)人員,你的目標(biāo)是構(gòu)造一個(gè)RuleExecutionSet對象,并在運(yùn)行時(shí)通過它獲得一個(gè)RuleSession對象。為了簡化這個(gè)過程, 我編寫了一個(gè)規(guī)則引擎API的fa?ade,可以用來解釋代表Drools的DRL文件的InputStream,并構(gòu)造一個(gè) RuleExecutionSet對象。
           在上面提到了Drools的三種語義模塊,我接下來使用它們重新編寫上面的例子XML規(guī)則文件。這個(gè)例子中我選擇Java模塊。使用Java模塊重新編寫的規(guī)則文件如下:

    <rule-set name="StockFlagger"
          xmlns="http://drools.org/rules"
          xmlns:java="http://drools.org/semantics/java">
      <rule name="FlagAsUndervalued">
        <parameter identifier="stock">
          <java:class>org.codehaus.drools.example.Stock</java:class>
        </parameter>
        <java:condition>stock.getIndexName().equals("DJIA");</java:condition>
        <java:condition>stock.getPE() > 10 </java:condition>
        <java:consequence>
          removeObject(stock);   ( 譯注:應(yīng)該是retractObject(stock) )
        </java:consequence>
      </rule>
    </rule-set>

           現(xiàn)在的規(guī)則文件并沒有上面的簡潔明了。別擔(dān)心,我們將在下一篇文章討論語義模塊。現(xiàn)在,請注意觀察XML文件的結(jié)構(gòu)。其中一個(gè)rule-set元素包含了 一個(gè)或多個(gè)rule元素,rule元素又包含了parameter,condition和consequence元素。Condition和 consequence元素包含的內(nèi)容和Java很象。注意,在這些元素中,有些事你可以做,有些事你不能做。目前,Drools使用 BeanShell2.0b1作為它的Java解釋器。我在這里并不想詳細(xì)的討論DRL文件和Java語義模塊的語法。我們的目標(biāo)是解釋如何使用 Drools的JSR94 API。
           在Drools項(xiàng)目CVS的drools-jsr94模塊中,單元測試代碼包含了一個(gè)ExampleRuleEngineFacade對象,它基于 Brian Topping的Dentaku項(xiàng)目。這個(gè)fa?ade對象通過javax.rules API,創(chuàng)建了供RuleExecutionSet和RuleSession使用的一系列對象。它并沒有完全包括了Drools引擎API的所有特性和細(xì) 微差別,但可以作為新手使用API的一個(gè)簡單例子。
          下面的代碼片斷顯示如何使用規(guī)則引擎的facade構(gòu)造一個(gè)RuleExecutionSet對象,并通過它獲得一個(gè)RuleSession對象。
     
    import java.io.InputStream;
    import javax.rules.*;
    import org.drools.jsr94.rules.ExampleRuleEngineFacade;
    public class Example {
        private ExampleRuleEngineFacade engine;
        private StatelessRuleSession statelessSession;
        /* place the rule file in the same package as this class */
        private String bindUri = "myRuleFile.drl"
        public Example() {
            /* get your engine facade */
            engine = new ExampleRuleEngineFacade();
            /* get your input stream */
            InputStream inputStream =
                    Example.class.getResourceAsStream(bindUri);
            /* build a RuleExecutionSet to the engine */
            engine.addRuleExecutionSet(bindUri, inputStream);
            /* don't forget to close your InputStream! */
            inputStream.close();
            /* get your runtime session */
            this.statelessSession = engine.getStatelessRuleSession(bindUri);
        }
        ...
    }

           在以上的例子代碼中,你需要處理InputStream的IOException例外,這里為了簡單起見省略了。你要做的只是構(gòu)建InputStream 對象,并把它輸入ExampleRuleEngineFacade,用來創(chuàng)建一個(gè)RuleExecutionSet對象。然后,你可以得到一個(gè) StatelessRuleSession,并用它來執(zhí)行所有的規(guī)則。使用StatelessRuleSession相對簡單。我們可以給上面的類添加一 個(gè)方法,用來對一個(gè)對象列表執(zhí)行規(guī)則:

    public List getUndervalued(List stocks) {
        return statelessSession.executeRules(stocks);
    }

           該方法輸入一個(gè)stock對象列表給規(guī)則引擎,然后使用規(guī)則評估輸入的股票對象,并剔除那些不符合價(jià)值低估標(biāo)準(zhǔn)的股票。它是個(gè)簡單的例子,但足以說明問題。
           在ExampleRuleEngineFacade類中,代碼會稍微有些復(fù)雜。ExampleRuleEngineFacade類創(chuàng)建了一個(gè) RuleServiceProvider對象,并用它創(chuàng)建RuleAdministrator,RuleExecutionSetProvider和 RuleRuntime對象。RuleExecutionSetProvider負(fù)責(zé)解釋InputStream,并創(chuàng)建一個(gè) RuleExecutionSet對象。RuleRuntime對象用來得到一個(gè)session,RuleAdministrator用來管理所有的對 象。在往下是Drools核心API,它的核心是Rete算法實(shí)現(xiàn)。我在這里不打算詳細(xì)討論,但你可以看看 ExampleRuleEngineFacade的代碼。
           現(xiàn)在你已經(jīng)看到了在商業(yè)和科研方面使用規(guī)則引擎的一些例子,并對Drools項(xiàng)目有了基本的了解。在下一篇文章里,我將討論DRL文件的結(jié)構(gòu)和Java語 義模塊,讓你可以編寫自己的DRL文件。還將向你解釋如何編寫你自己的語義模塊,討論salience和working memory的概念。

    資源
    · Drools Project
    · JSR-94 Specification
     
    作者
          N. Alex Rupp is a freelance software architect and developer from Minneapolis, and the current JSR94 Lead for the Drools project.
    posted @ 2006-03-11 10:00 Dion 閱讀(1750) | 評論 (0)編輯 收藏

    一般情況下, 只顯式引用:

    • drools-all-2.0.jar
    • antlr-2.7.5.jar
    • xercesImpl-2.6.2.jar

    就可以了.當(dāng)然ClassPath下也要用一些其他的jar.
    下載位置: http://dist.codehaus.org/drools/distributions/drools-2.0-bin-withdeps.zip

    如果, 在DRL文件中定義了Java Function, 這時(shí)候就要顯式的引用:

    • janino-2.3.2.jar

    這時(shí)候, 引擎是需要janino把DRL中的java function描述轉(zhuǎn)換成可執(zhí)行的二進(jìn)制代碼(?)的.

    posted @ 2006-03-11 09:59 Dion 閱讀(962) | 評論 (0)編輯 收藏

    Drools and Mandarax

    兩個(gè)項(xiàng)目做了兩件不同的事情: 一個(gè)是Forward Chaining,另一個(gè)是 backward chaining. Drools 是forward chaining的,  意味著 它對assert的對象反應(yīng), 事件驅(qū)動的. Mandarax 是 backward chaining的, 像 prologue一樣, 你問它問題, 它試圖給你它知道的答案. 舉例來說, 在使用Drools的時(shí)候, 你可能會先assert 給它今天的日期, 如果它發(fā)現(xiàn)有匹配的規(guī)則的手,它會用事件的方式通知你"今天是你的生日". 在 backward chaining 的系統(tǒng), 你可能先問 "今天是我的生日嘛?" 系統(tǒng)會搜索它知道的, 然后告訴你答案.
    For an excellent explanation of forward and backward chaining read Charles Forgey's recent articles at http://rulespower.com/ - Forward and Backward Chaining:
    Parts 1, 2 and 3.
    posted @ 2006-03-11 09:58 Dion 閱讀(1173) | 評論 (0)編輯 收藏

    Open Source Rule Engines Written In Java

    • Drools The drools engine uses a modified form of the Rete algorithm called the Rete-OO algorithm. Internally it operates using the same concepts and methods as Forgy's original but adds some node types required for seemless integration with an object-oriented language.
    • OFBiz Rule Engine Backward chaining is supported. Original code base from "Building Parsers in Java" by Steven John Metsker.
    • Mandarax Based on backward reasoning. The easy integration of all kinds of data sources. E.g., database records can be easily integrated as sets of facts and reflection is used in order to integrate functionality available in the object model.
    • Algernon Efficient and concise KB traversal and retrieval. Straightforward access to ontology classes and instances. Supports both forward and backward chaining.
    • TyRuBa TyRuBa supports higher order logic programming: variables and compound terms are allowed everywhere in queries and rules, also in the position of a functor- or predicate-name. TyRuBa speeds up execution by making specialized copies of the rule-base for each query in the program. It does so incrementally while executing a logic program and builds an index for fast access to rules and facts in the rule base, tuned to the program that is running. The indexing techniques works also for higher-order logic. TyRuBa does 'tabling' of query results.
    • JTP Java Theorem Prover is based on a very simple and general reasoning architecture. The modular character of the architecture makes it easy to extend the system by adding new reasoning modules (reasoners), or by customizing or rearranging existing ones.
    • JEOPS JEOPS adds forward chaining, first-order production rules to Java through a set of classes designed to provide this language with some kind of declarative programming.
    • InfoSapient Semantics of business rules expressed using fuzzy logic.
    • JShop Simple Hierarchical Ordered Planner (SHOP) written in Java.
    • RDFExpert RDF-driven expert system shell. The RDFExpert software uses Brian McBride's JENA API and parser. A simple expert system shell that uses RDF for all of its input: knowledge base, inference rules and elements of the resolution strategy employed. It supports forward and backward chaining.
    • Jena 2 - Jena is a Java framework for writing Semantic Web applications. Jena2 has a reasoner subsystem which includes a generic rule based inference engine together with configured rule sets for RDFS and for the OWL/Lite subset of OWL Full. These reasoners can be used to construct inference models which show the RDF statements entailed by the data being reasoned over. The subsystem is designed to be extensible so that it should be possible to plug a range of external reasoners into Jena, though worked examples of doing so are left to a future release.
    • JLisa - JLisa is a powerful framework for building business rules accessible to Java and it is compatible with JSR-94. JLisa is more powerful than Clips because it has the expanded benefit of having all the features from common lisp available. These features are essential for multi-paradigm software development
    • Euler - Euler is a backward-chaining reasoner enhanced with Euler path detection and will tell you whether a given set of facts and rules supports a given conclusion. Things are described in N3.
    • JLog - JLog is an implementation of a Prolog interpreter, written in Java. It includes built-in source editor, query panels, online help, animation primitives, and a GUI debugger.
    • Pellet OWL Reasoner - Pellet is an open-source Java based OWL DL reasoner. It can be used in conjunction with either Jena or OWL API libraries. Pellet API provides functionalities to see the species validation, check consistency of ontologies, classify the taxonomy, check entailments and answer a subset of RDQL queries (known as ABox queries in DL terminology). Pellet is an OWL DL reasoner based on the tableaux algorithms developed for expressive Description Logics.
    • Prova - Prova is derived from Mandarax Java-based inference system developed by Jens Dietrich. Prova extends Mandarax by providing a proper language syntax, native syntax integration with Java, and agent messaging and reaction rules. The development of this language was supported by the grant provided within the EU project GeneStream. In the project, the language is used as a rules-based backbone for distributed web applications in biomedical data integration.
    posted @ 2006-03-11 09:58 Dion 閱讀(1342) | 評論 (0)編輯 收藏

    始終會用上的Common BeanUtils

    Beanutils用了魔術(shù)般的反射技術(shù),實(shí)現(xiàn)了很多夸張有用的功能,都是C/C++時(shí)代不敢想的。無論誰的項(xiàng)目,始終一天都會用得上它。我算是后知后覺了,第一回看到它的時(shí)候居然錯(cuò)過。

    1.屬性的動態(tài)getter、setter

    在這框架滿天飛的年代,不能事事都保證執(zhí)行g(shù)etter,setter函數(shù)了,有時(shí)候?qū)傩允且鶕?jù)名字動態(tài)取得的,就像這樣:  
    BeanUtils.getProperty(myBean,"code");
    而Common BeanUtils的更強(qiáng)功能在于可以直接訪問內(nèi)嵌對象的屬性,只要使用點(diǎn)號分隔。
    BeanUtils.getProperty(orderBean, "address.city");
    相比之下其他類庫的BeanUtils通常都很簡單,不能訪問內(nèi)嵌的對象,所以有時(shí)要用Commons BeanUtils來替換它們。

    BeanUtils還支持List和Map類型的屬性,如下面的語法即可取得Order的顧客列表中第一個(gè)顧客的名字
    BeanUtils.getProperty(orderBean, "customers[1].name");
    其中BeanUtils會使用ConvertUtils類把字符串轉(zhuǎn)為Bean屬性的真正類型,方便從HttpServletRequest等對象中提取bean,或者把bean輸出到頁面。
    而PropertyUtils就會原色的保留Bean原來的類型。

    2.BeanCompartor 動態(tài)排序

    還是通過反射,動態(tài)設(shè)定Bean按照哪個(gè)屬性來排序,而不再需要在實(shí)現(xiàn)bean的Compare接口進(jìn)行復(fù)雜的條件判斷。
    List peoples = ...; // Person對象的列表
    Collections.sort(peoples, new BeanComparator("age"));

    如果要支持多個(gè)屬性的復(fù)合排序,如"Order By lastName,firstName"

    ArrayList sortFields = new ArrayList();
    sortFields.add(new BeanComparator("lastName"));
    sortFields.add(new BeanComparator("firstName"));
    ComparatorChain multiSort = new ComparatorChain(sortFields);
    Collections.sort(rows,multiSort);

    其中ComparatorChain屬于jakata commons-collections包。
    如果age屬性不是普通類型,構(gòu)造函數(shù)需要再傳入一個(gè)comparator對象為age變量排序。
    另外, BeanCompartor本身的ComparebleComparator, 遇到屬性為null就會拋出異常, 也不能設(shè)定升序還是降序。這個(gè)時(shí)候又要借助commons-collections包的ComparatorUtils.

       Comparator mycmp = ComparableComparator.getInstance();
       mycmp = ComparatorUtils.nullLowComparator(mycmp);  //允許null
       mycmp = ComparatorUtils.reversedComparator(mycmp); //逆序
       Comparator cmp = new BeanComparator(sortColumn, mycmp);
    3.Converter 把Request或ResultSet中的字符串綁定到對象的屬性

       經(jīng)常要從request,resultSet等對象取出值來賦入bean中,如果不用MVC框架的綁定功能的話,下面的代碼誰都寫膩了。

       String a = request.getParameter("a");
    bean.setA(a);
    String b = ....
    bean.setB(b);
    ......

    不妨寫一個(gè)Binder自動綁定所有屬性:

        MyBean bean = ...;
    HashMap map = new HashMap();
    Enumeration names = request.getParameterNames();
    while (names.hasMoreElements())
    {
    String name = (String) names.nextElement();
    map.put(name, request.getParameterValues(name));
    }
    BeanUtils.populate(bean, map);

        其中BeanUtils的populate方法或者getProperty,setProperty方法其實(shí)都會調(diào)用convert進(jìn)行轉(zhuǎn)換。
         但Converter只支持一些基本的類型,甚至連java.util.Date類型也不支持。而且它比較笨的一個(gè)地方是當(dāng)遇到不認(rèn)識的類型時(shí),居然會拋 出異常來。 對于Date類型,我參考它的sqldate類型實(shí)現(xiàn)了一個(gè)Converter,而且添加了一個(gè)設(shè)置日期格式的函數(shù)。
    要把這個(gè)Converter注冊,需要如下語句:

        ConvertUtilsBean convertUtils = new ConvertUtilsBean();
       DateConverter dateConverter = new DateConverter();
       convertUtils.register(dateConverter,Date.class);



    //因?yàn)橐詂onverter,所以不能再使用BeanUtils的靜態(tài)方法了,必須創(chuàng)建BeanUtilsBean實(shí)例
    BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils,new PropertyUtilsBean());
    beanUtils.setProperty(bean, name, value);
    4 其他功能
    4.1 ConstructorUtils,動態(tài)創(chuàng)建對象
         public static Object invokeConstructor(Class klass, Object arg)
    4.2 MethodUtils,動態(tài)調(diào)用方法
        MethodUtils.invokeMethod(bean, methodName, parameter);

    4.3 PropertyUtils,當(dāng)屬性為Collection,Map時(shí)的動態(tài)讀取:
    Collection: 提供index
       BeanUtils.getIndexedProperty(orderBean,"items",1);
    或者
      BeanUtils.getIndexedProperty(orderBean,"items[1]");
    Map: 提供Key Value
      BeanUtils.getMappedProperty(orderBean, "items","111");//key-value goods_no=111 
    或者
      BeanUtils.getMappedProperty(orderBean, "items(111)") 

    4.4 PropertyUtils,直接獲取屬性的Class類型
         public static Class getPropertyType(Object bean, String name)
    4.5 動態(tài)Bean 用DynaBean減除不必要的VO和FormBean 
    posted @ 2006-01-15 20:20 Dion 閱讀(5093) | 評論 (2)編輯 收藏

         摘要: Migrate apps from Internet Explorer to MozillaHow to make Internet Explorer-specific Web applications work in Mozilla-based browsersDocument options Print this page'); //--> Print this page E-ma...  閱讀全文
    posted @ 2006-01-04 19:18 Dion 閱讀(1490) | 評論 (1)編輯 收藏

    以下以 IE 代替 Internet Explorer,以 MF 代替 Mozzila Firefox

    1. document.form.item 問題
        (1)現(xiàn)有問題:
            現(xiàn)有代碼中存在許多 document.formName.item("itemName") 這樣的語句,不能在 MF 下運(yùn)行
        (2)解決方法:
            改用 document.formName.elements["elementName"]
        (3)其它
            參見 2

    2. 集合類對象問題
        (1)現(xiàn)有問題:
            現(xiàn)有代碼中許多集合類對象取用時(shí)使用 (),IE 能接受,MF 不能。
        (2)解決方法:
            改用 [] 作為下標(biāo)運(yùn)算。如:document.forms("formName") 改為 document.forms["formName"]。
            又如:document.getElementsByName("inputName")(1) 改為 document.getElementsByName("inputName")[1]
        (3)其它

    3. window.event
        (1)現(xiàn)有問題:
            使用 window.event 無法在 MF 上運(yùn)行
        (2)解決方法:
            MF 的 event 只能在事件發(fā)生的現(xiàn)場使用,此問題暫無法解決。可以這樣變通:
            原代碼(可在IE中運(yùn)行):
                <input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit()"/>
                ...
                <script language="javascript">
                    function gotoSubmit() {
                        ...
                        alert(window.event);    // use window.event
                        ...
                    }
                </script>

            新代碼(可在IE和MF中運(yùn)行):
                <input type="button" name="someButton" value="提交" onclick="javascript:gotoSubmit(event)"/>
                ...
                <script language="javascript">
                    function gotoSubmit(evt) {
                        evt = evt ? evt : (window.event ? window.event : null);
                        ...
                        alert(evt);             // use evt
                        ...
                    }
                </script>
            此外,如果新代碼中第一行不改,與老代碼一樣的話(即 gotoSubmit 調(diào)用沒有給參數(shù)),則仍然只能在IE中運(yùn)行,但不會出錯(cuò)。所以,這種方案 tpl 部分仍與老代碼兼容。

    4. HTML 對象的 id 作為對象名的問題
        (1)現(xiàn)有問題
            在 IE 中,HTML 對象的 ID 可以作為 document 的下屬對象變量名直接使用。在 MF 中不能。
        (2)解決方法
            用 getElementById("idName") 代替 idName 作為對象變量使用。

    5. 用idName字符串取得對象的問題
        (1)現(xiàn)有問題
            在IE中,利用 eval(idName) 可以取得 id 為 idName 的 HTML 對象,在MF 中不能。
        (2)解決方法
            用 getElementById(idName) 代替 eval(idName)。

    6. 變量名與某 HTML 對象 id 相同的問題
        (1)現(xiàn)有問題
            在 MF 中,因?yàn)閷ο?id 不作為 HTML 對象的名稱,所以可以使用與 HTML 對象 id 相同的變量名,IE 中不能。
        (2)解決方法
            在聲明變量時(shí),一律加上 var ,以避免歧義,這樣在 IE 中亦可正常運(yùn)行。
            此外,最好不要取與 HTML 對象 id 相同的變量名,以減少錯(cuò)誤。
        (3)其它
            參見 問題4

    7. event.x 與 event.y 問題
        (1)現(xiàn)有問題
            在IE 中,event 對象有 x, y 屬性,MF中沒有。
        (2)解決方法
            在MF中,與event.x 等效的是 event.pageX。但event.pageX IE中沒有。
            故采用 event.clientX 代替 event.x。在IE 中也有這個(gè)變量。
            event.clientX 與 event.pageX 有微妙的差別(當(dāng)整個(gè)頁面有滾動條的時(shí)候),不過大多數(shù)時(shí)候是等效的。

            如果要完全一樣,可以稍麻煩些:
            mX = event.x ? event.x : event.pageX;
            然后用 mX 代替 event.x
        (3)其它
            event.layerX 在 IE 與 MF 中都有,具體意義有無差別尚未試驗(yàn)。


    8. 關(guān)于frame
       (1)現(xiàn)有問題
             在 IE中 可以用window.testFrame取得該frame,mf中不行
       (2)解決方法
             在frame的使用方面mf和ie的最主要的區(qū)別是:
    如果在frame標(biāo)簽中書寫了以下屬性:
    <frame src="xx.htm" id="frameId" name="frameName" />
    那么ie可以通過id或者name訪問這個(gè)frame對應(yīng)的window對象
    而mf只可以通過name來訪問這個(gè)frame對應(yīng)的window對象
    例如如果上述frame標(biāo)簽寫在最上層的window里面的htm里面,那么可以這樣訪問
    ie: window.top.frameId或者window.top.frameName來訪問這個(gè)window對象
    mf: 只能這樣window.top.frameName來訪問這個(gè)window對象

    另外,在mf和ie中都可以使用window.top.document.getElementById("frameId")來訪問frame標(biāo)簽
    并且可以通過window.top.document.getElementById("testFrame").src = 'xx.htm'來切換frame的內(nèi)容
    也都可以通過window.top.frameName.location = 'xx.htm'來切換frame的內(nèi)容
    關(guān)于frame和window的描述可以參見bbs的‘window與frame’文章
    以及/test/js/test_frame/目錄下面的測試
    ----adun 2004.12.09修改

    9. 在mf中,自己定義的屬性必須getAttribute()取得
    10.在mf中沒有  parentElement parement.children  而用
                   parentNode parentNode.childNodes
       childNodes的下標(biāo)的含義在IE和MF中不同,MF使用DOM規(guī)范,childNodes中會插入空白文本節(jié)點(diǎn)。
      一般可以通過node.getElementsByTagName()來回避這個(gè)問題。
       當(dāng)html中節(jié)點(diǎn)缺失時(shí),IE和MF對parentNode的解釋不同,例如
       <form>
       <table>
            <input/>
       </table>
       </form>
       MF中input.parentNode的值為form, 而IE中input.parentNode的值為空節(jié)點(diǎn)

      MF中節(jié)點(diǎn)沒有removeNode方法,必須使用如下方法 node.parentNode.removeChild(node)

    11.const 問題
      (1)現(xiàn)有問題:
         在 IE 中不能使用 const 關(guān)鍵字。如 const constVar = 32; 在IE中這是語法錯(cuò)誤。
      (2)解決方法:
         不使用 const ,以 var 代替。

    12. body 對象
       MF的body在body標(biāo)簽沒有被瀏覽器完全讀入之前就存在,而IE則必須在body完全被讀入之后才存在

    13. url encoding
    在js中如果書寫url就直接寫&不要寫&amp;例如var url = 'xx.jsp?objectName=xx&amp;objectEvent=xxx';
    frm.action = url那么很有可能url不會被正常顯示以至于參數(shù)沒有正確的傳到服務(wù)器
    一般會服務(wù)器報(bào)錯(cuò)參數(shù)沒有找到
    當(dāng)然如果是在tpl中例外,因?yàn)閠pl中符合xml規(guī)范,要求&書寫為&amp;
    一般MF無法識別js中的&amp;


    14. nodeName 和 tagName 問題
      (1)現(xiàn)有問題:
         在MF中,所有節(jié)點(diǎn)均有 nodeName 值,但 textNode 沒有 tagName 值。在 IE 中,nodeName 的使用好象
         有問題(具體情況沒有測試,但我的IE已經(jīng)死了好幾次)。
      (2)解決方法:
         使用 tagName,但應(yīng)檢測其是否為空。

    15. 元素屬性
       IE下 input.type屬性為只讀,但是MF下可以修改


    16. document.getElementsByName() 和 document.all[name] 的問題
      (1)現(xiàn)有問題:
         在 IE 中,getElementsByName()、document.all[name] 均不能用來取得 div 元素(是否還有其它不能取的元素還不知道)。
    posted @ 2005-12-31 17:55 Dion 閱讀(934) | 評論 (1)編輯 收藏

    這里說說我的經(jīng)歷吧。大學(xué)前以及大學(xué)前面三年的經(jīng)歷就不說了,因?yàn)榇髮W(xué)前的高中就是好好學(xué)習(xí),大學(xué)前三年就是混過來的。

        我上的學(xué)校還算可以,雖然不是北大清華這樣第一流名牌大學(xué),但至少也算中國的第二流名牌大學(xué)了。大學(xué)中前面三年都陪伴著游戲過去,所學(xué)到的只是些計(jì)算機(jī)基 礎(chǔ)知識。到大四后我突然發(fā)現(xiàn)就業(yè)的問題就在眼前,而自己似乎什么也不會,于是開始看書。最一開始重點(diǎn)看的是C++,可是后來自從看了一本J2ME的書以后 被Java所吸引。當(dāng)時(shí)雖然學(xué)校上過Java課程,但是自己也只是學(xué)了很少的皮毛,也就只會寫寫Hello World和什么加減法之類很簡單的程序,連API都知道沒有幾個(gè),比如說字符串長度的API我都不知道。所以剛開始自己學(xué)J2ME的時(shí)候?qū)覍沂艽欤约? 也明白自己的缺點(diǎn),決定從J2SE開始好好補(bǔ)上。

        剛開始為了熟悉Java開發(fā)環(huán)境,買了本JBuilder開發(fā)的教程,并且在自己的本本上安裝了JBuilder進(jìn)行演練。當(dāng)時(shí)的我連JavaDoc都不 知道,每次究竟什么API能做什么事情一點(diǎn)頭緒都沒有,還不知道哪里去查,后來同學(xué)告訴我有個(gè)JavaDoc這個(gè)東西,我還興奮不已,覺得自己被從黑暗中 拉回來了。一開始使用JBuilder的時(shí)候,馬上為之所吸引,有兩個(gè)原因,第一是因?yàn)樗詣訕?biāo)出語法錯(cuò)誤,邊寫代碼邊提示你什么地方語法出錯(cuò),記得以前 使用VC++的時(shí)候,每次程序?qū)懞煤笙染幾g,然后再Build,再運(yùn)行,這其中每個(gè)步驟都會出不少錯(cuò)誤。特別是在編譯的時(shí)候,寫個(gè)200多行的程序一次編 譯下來就有100多個(gè)錯(cuò)誤,結(jié)果每次花在這上面的工夫都要好長時(shí)間。而JBuilder使用了即時(shí)語法分析,所以基本上程序?qū)懲辏涂梢允÷哉{(diào)試語法錯(cuò)誤 的步驟了。第二個(gè)原因是可以自動提示代碼,這個(gè)功能可以讓你迅速熟悉API,免得每次去查幫助文檔那么麻煩,我就是這么很快掌握了許多API的。

    可能大家會問我為什么一開始不學(xué)習(xí)《Java編程思想》,的確這本書我們宿舍就有好幾本,不過大家普遍反映效果不好,到最后都不知道說的是什么,所以我也沒敢看。

        經(jīng)過20天左右的學(xué)習(xí),對Java有了更進(jìn)一步的了解,熟悉了不少API函數(shù),由于在那本書上寫開發(fā)SWING占了不少篇幅,所以也對Swing的開發(fā)了 解了不少。看完以后因?yàn)橥瑢W(xué)說Java的靈魂就是多線程編程,所以開始看Oreilly的《Java線程》。記得在大學(xué)中操作系統(tǒng)這門課我們就提到過線程 的知識。并且課本上就是用Java實(shí)現(xiàn)的,當(dāng)時(shí)有了一點(diǎn)點(diǎn)概念,但這次看這本專門說線程的書后才發(fā)現(xiàn)我原來了解的那些根本是什么都不算(當(dāng)然,現(xiàn)在回想起 來,我那時(shí)看書學(xué)到的也只是很簡單的皮毛而已)。看完這本書后我自己學(xué)會在我的JBuilder下開發(fā)很簡單的多線程程序,并且模擬線程沖突,等待等情 況。當(dāng)時(shí)看著自己寫的一兩百行程序可以順利執(zhí)行,那種興奮勁就別提了。這本書我看得也很快,大概就花了3個(gè)星期看完。

        經(jīng)過上面的學(xué)習(xí),自己相比以前來說提升了不少,這時(shí)候自己也找到了工作,是做J2EE對日外包的,所以更加堅(jiān)定了努力學(xué)習(xí)Java的信心。

        在上面寫的程序中,我自己寫程序沒有規(guī)范性,在代碼編寫的時(shí)候自己的盲點(diǎn)特別多,還容易犯低級失誤。同學(xué)有一個(gè)《Effective Java》中文版,可是我看了幾頁發(fā)現(xiàn)自己根本看不懂,里面什么靜態(tài)工廠啊,什么單例模式什么的根本不知道什么東東。我知道自己目前的水平還不夠,所以決 定放下這本書,去尋找別的適合我的書看。這個(gè)時(shí)候我看到了候捷先生翻譯的《Practical Java》一書,當(dāng)時(shí)是剛剛上的書架。這本書我在書店翻了下目錄后就感覺如獲至寶,馬上買回家,在回家的公車上就貪婪地讀起來。這本書不算很厚,但是自己 看得卻很認(rèn)真很仔細(xì),也明白了不少東西,比如Java中等號和equals()方法的區(qū)別,究竟什么時(shí)候用什么。還有Exception處理機(jī)制,以前不 知道什么叫Exception,只是JBuilder提示我要我拋出Exception我再拋出Exception,自己覺得這東西基本沒什么用呢。但是 看了這本書后我改變了看法,我發(fā)現(xiàn)Exception是個(gè)很好的東西,可以迅速把程序從正常狀態(tài)和異常狀態(tài)區(qū)分開來,即使而準(zhǔn)確地在指定位置得到處理。那 時(shí)自己也有了以后寫程序的時(shí)候注意編寫異常處理部分的想法。《Practical Java》這本書雖然不厚,但是我卻非常仔細(xì)地去看了,大概花了1個(gè)月時(shí)間,我把這本書完全消化了下去。

        當(dāng)時(shí)聽說Java在網(wǎng)絡(luò)上的應(yīng)用非常廣,我也不知道究竟是什么應(yīng)用,我于是買了Oreilly的《Java網(wǎng)絡(luò)編程》這本書。這本書雖然很厚,其實(shí)前半部 分內(nèi)容不是很復(fù)雜,后半部分寫什么RMI的東西我也看不大懂,只能理解個(gè)概念。通過這本書,我了解了HTTP協(xié)議究竟是什么一個(gè)東西,在它上面利用 Java傳輸數(shù)據(jù)該如何做,知道了什么是Request,什么是Response。這也為以后開始我的J2EE之旅打下了很好的基礎(chǔ)。當(dāng)時(shí)自己依然是邊看 書邊自己寫代碼來驗(yàn)證,自己寫了個(gè)服務(wù)器端Socket和客戶端Socket,成功進(jìn)行了通信,又在上面加上了安全Socket內(nèi)容,實(shí)現(xiàn)了SSL通信。 當(dāng)時(shí)我把寫的這個(gè)又套上了Swing的外殼,還和同學(xué)拿這個(gè)傳文件呢。不過當(dāng)時(shí)也沒有考慮過什么校驗(yàn)碼之類的東西,所以傳傳小文件還是可以的,文件稍微一 大一點(diǎn),傳過去的文件總是不對頭,和我原來的文件經(jīng)常會出一些差異,導(dǎo)致文件打不開。

        《Java網(wǎng)絡(luò)編程》這本書看了不少時(shí)間,因?yàn)闀容^厚,東西也比較多,不過除了后面的一些知識以外,其他的還是容易理解的。大概花了2個(gè)月左右的時(shí)間看 完。看完后,時(shí)間也到了2004年的3月。我也輪到開始我畢業(yè)設(shè)計(jì)的時(shí)候了。我們的畢業(yè)設(shè)計(jì)導(dǎo)師都還不錯(cuò),給你自己選個(gè)課題,我選的是一個(gè)B/S結(jié)構(gòu)的在 線簡歷處理系統(tǒng),正好和我所學(xué)和下面所工作的東西是一條路上的了。這時(shí)我覺得我應(yīng)該往B/S結(jié)構(gòu)上轉(zhuǎn)了,當(dāng)時(shí)在選擇先看Servlet還是先看JSP上猶 豫不決。最終決定先看Servlet,后來也證明了我的決定是對的,我在熟悉了Servlet后再學(xué)JSP是非常容易的,基本上根本沒有遇到什么難點(diǎn)。

    可 能有人會覺得我看了好多Oreilly的書,雖然我不能說Oreilly本本都是好書,不過相對來說,好書的概率總超過許多其他的出版社,而且體系比較齊 全。我看得幾本書我都覺得還不錯(cuò)。現(xiàn)說說下面這本我學(xué)Servlet時(shí)候看的《Java Servlet編程》來說吧,很不錯(cuò)的一本書,讓我迅速知道了什么是Servlet,然后通過最簡單的實(shí)例,讓你知道了Servlet如何運(yùn)行的,跟 HTTP協(xié)議是如何配合的,如何返回HTML形式的文本,XML配置符該如何寫,究竟每個(gè)元素是什么意思等等。由于我原來有一定的XML基礎(chǔ)(知道XML 語法各種格式的含義而已),所以掌握起來還算比較快。通過這本書,我知道了如何動態(tài)生成HTML文檔,知道如何把一個(gè)Servlet映射到一個(gè)虛擬的地 址。在后半部分寫到了數(shù)據(jù)庫操作部分,我對數(shù)據(jù)庫的了解其實(shí)也僅限于原來大學(xué)課本上的《數(shù)據(jù)庫系統(tǒng)原理》,如何從程序和數(shù)據(jù)庫交互是一竅不通。通過數(shù)據(jù)庫 操作這章,我知道了如何使用JDBC語句如何編寫,大家不要笑,對于當(dāng)初一個(gè)新手來說,這個(gè)真是一個(gè)全新的領(lǐng)域,做什么事情都需要Sample來對照,跟 著依葫蘆畫瓢吧,其實(shí)現(xiàn)在的軟件開發(fā)也是這樣,我想現(xiàn)在大家誰能直接手寫Struts或者Hibernate的配置文件都很難吧。閑話少說,大概這個(gè)時(shí) 候,我對畢業(yè)設(shè)計(jì)的雛形有了點(diǎn)思想上的概念。看完了《Java Servlet編程》后緊接著就又看Oreilly的《JSP設(shè)計(jì)》,由于有了Servlet的基礎(chǔ),學(xué)起JSP特別快。當(dāng)時(shí)沒有著重看Tag的自定義設(shè) 計(jì),光看了JSP的其他東西,終于在五一節(jié)后把畢業(yè)設(shè)計(jì)都寫完了,當(dāng)時(shí)總代碼量是2000多行,第一次寫這么多代碼的程序覺得很有成就感。現(xiàn)在看起來那時(shí) 做的是標(biāo)準(zhǔn)垃圾,但是當(dāng)時(shí)覺得還是很不錯(cuò)。用了Servlet + JSP。其實(shí)Servlet也不是用來當(dāng)控制器的,而是和JSP做的差不多功能,都是作view的功能的。很快,畢業(yè)設(shè)計(jì)交差過去了,寫寫畢業(yè)論文,準(zhǔn)備 答辯。在這個(gè)過程中,我又一次考慮自己下面該看什么書。

    這次我又看中了侯捷翻譯的一本巨著,也就是鼎鼎大名的Martin Fowler寫的《重構(gòu)——改善既有代碼的設(shè)計(jì)》這本書。剛開始聽見重構(gòu)這個(gè)名字,總覺得非常高深,加上都評論說重構(gòu)是和設(shè)計(jì)模式齊名的東東,感覺更加高 深恐怖了。大概在6月初我開始看了重構(gòu),剛開始看的時(shí)候雖然抱著試試看的心態(tài),不過還是非常認(rèn)真的。但是,讓我頗感意外的是重構(gòu)并不是很難,至少這本書中 說的非常通俗易懂,通過大量的實(shí)例讓你覺得重構(gòu)是種很簡單很基本的技術(shù)。雖然我看完了重構(gòu)以后在真實(shí)的代碼編寫中很少直接按照上面代碼所說的方法進(jìn)行重構(gòu) 代碼,基本上都是通過IDE來重構(gòu)代碼,但是卻大大提升了自己編程思維,從此以后寫代碼就很少瞻前顧后了,因?yàn)槲覔碛辛酥貥?gòu)這個(gè)工具。這本書有點(diǎn)厚,再加 上中間有答辯,拍畢業(yè)照,以及畢業(yè)手續(xù)等等,這本書我花了一個(gè)半月看完。我看書的速度也不算快,不過我看書比較有恒心,不像有部分人看幾天就不想看了,我 能堅(jiān)持天天看,所以總的來說還是不慢的。我計(jì)算過,如果我每天看10頁書,堅(jiān)持下去,那一年就是3650頁書,平均一本書365頁來算,1年就是10本。 如果這10本書中有8本不屬于垃圾書籍,那么你這年就能有非常大的提高了。

    看重構(gòu)這本書中間我也抽了一段時(shí)間看了兩本其他的書,第一本是 《Java夜未眠》,挺不錯(cuò)的一本書,雖然是散文,但是還是能讓你明白不少道理,受益匪淺。另外一本就是李維的《Borland傳奇》,由于自己當(dāng)時(shí)最喜 歡用的工具就是JBuilder,所以也對Borland公司非常敬仰,特別對安德森,簡直就頂禮膜拜啊,哈哈。這本書寫得很精彩,寫了Borland公 司二十年來的血淚史,寫了如何跟微軟斗爭,如何在微軟和IBM的夾縫中生存。當(dāng)然,也有很多的對于技術(shù)方面作者李維自己的見解,看了會有不少同感的。就這 樣,磨磨蹭蹭地把重構(gòu)看完了。

        當(dāng)看完了《重構(gòu)》這本書之后,我也開始去公司報(bào)到上班了。可以看出來,我當(dāng)時(shí)工作的時(shí)候水平也很有限,但總比一年前要好不少,至少很多東西都已經(jīng)知道了。 那時(shí)外面極限編程聽的比較多,自己也去書店買了本《Java極限編程》回來看,現(xiàn)在想想算是我看得第一本垃圾書籍了。不過也是有收獲的,這本書極限編程也 就說了點(diǎn)概念,然后就寫了不少工具的使用方法。在看《重構(gòu)》中對JUnit有了點(diǎn)認(rèn)識,不過只是皮毛中的皮毛。看了這本《Java極限編程》后對 JUnit的使用又了解了不少皮毛,對于Cactus有了點(diǎn)了解,對Ant了解了不少,至少可以自己寫出自己需要的配置文件了,并且可以結(jié)合JUnit生 成測試Report。由于我去的是日企,做對日外包的,所以公司開始培訓(xùn)日本語,用的是《標(biāo)準(zhǔn)日本語》這套教材。我于是邊學(xué)日語邊看技術(shù),大概2個(gè)星期左 右我把那本《Java極限編程》初步看完后就扔在了家里。這時(shí)的我已經(jīng)開始會用Ant了,覺得是步入J2EE的重要一步。

        很快啃掉那本垃圾書以后又看了本和Java不是非常有關(guān)的書:《程序員修煉之道——從小工到專家》,原因其實(shí)很簡單,大學(xué)同學(xué)都說這本書是經(jīng)典書,看書這 東西,別人的評價(jià)還是能起不少作用的。這本書字?jǐn)?shù)不是很多,不過排版的時(shí)候比較分散,導(dǎo)致書本有點(diǎn)厚,呵呵,可能也算出版社賺錢的一種方法吧。不過總的來 說,我覺得出版社紙張質(zhì)量最好的是電子工業(yè)出版社,其次是中國電力出版社,最爛的恐怕就是機(jī)械工業(yè)出版社了,機(jī)械工業(yè)出版社有少量書紙張還能說過去,但有 不少簡直讓人不得不有脾氣啊,紙張薄得感覺和寫毛筆字的宣紙都差不多了。這本電子工業(yè)出版社的書紙張質(zhì)量的確不錯(cuò),不過也許是因?yàn)槲夜αι袦\,所以這本書 雖然都看懂了,但是深有感觸并且銘記于心的沒有幾個(gè),現(xiàn)在再回想,也只記得軟件模塊設(shè)計(jì)時(shí)要正交等等少數(shù)幾點(diǎn)了。這本書由于內(nèi)容不是非常多,所以我就看了 半個(gè)月不到搞定。這時(shí)的我開發(fā)IDE已經(jīng)轉(zhuǎn)移到了Eclipse上,畢竟商業(yè)開發(fā)用D版有點(diǎn)說不過去,而且公司也怕查,所以不允許用JBuilder,鼓 勵(lì)大家用Eclipse。我用了一段時(shí)間的Eclipse后,從一開始的不適應(yīng)到后來覺得Eclipse很方便使用,JBuilder比Eclipse多 的就是一些根據(jù)不同類型開發(fā)的模版而已,而這些可以由Eclipse的插件來彌補(bǔ)。到了這時(shí),我覺得我的Java基礎(chǔ)應(yīng)該算還可以的了,API也熟悉了非 常多。我覺得看《Effective Java》的時(shí)機(jī)成熟了。

        由于大學(xué)已經(jīng)畢業(yè)了,所以也不會有同學(xué)的《Effective Java》放在邊上讓我看這樣的好事出現(xiàn),老老實(shí)實(shí)地去了書店買了本《Effective Java》中文版回來研讀。呵呵,大家也許會問我為什么不買本E文的看,雖然我大學(xué)早早也把英語4級過了,而且大學(xué)中不少計(jì)算機(jī)專業(yè)課程教材也是E文的, 當(dāng)時(shí)為了考試也認(rèn)真讀了。但是畢竟英語不是我們的母語,看起來速度上明顯比中文版的慢一截。當(dāng)然,如果是那種垃圾翻譯者用機(jī)器翻譯出來的中文版,看那些垃 圾中文版速度肯定比不上直接看英文原版的。這時(shí)的我看《Effective Java》已經(jīng)不再是當(dāng)初的那么感覺很陌生了,覺得上面說的那些要點(diǎn)自己想想還都是可以理解的。我個(gè)人覺得提高自身編程習(xí)慣以及水平最多的還是看類似于 《Practical Java》和《Effective Java》的這種按照條目來進(jìn)行說明的書,能把你自己平時(shí)容易忽略的地方按照重點(diǎn)一個(gè)個(gè)揪出來進(jìn)行修正。比如《Effective Java》中的第一條,使用靜態(tài)工廠來代替構(gòu)造函數(shù),自己原來在進(jìn)行開發(fā)的時(shí)候,從來不怎么會主動想到建立一個(gè)靜態(tài)工廠,總覺得使用構(gòu)造函數(shù)來新建一個(gè)對 象是天經(jīng)地義的事情。但看完這個(gè)條目后,我的看法也隨之改變,發(fā)現(xiàn)靜態(tài)工廠還是非常好的,當(dāng)然,也不是什么地方用靜態(tài)工廠都很好。上面也寫到了靜態(tài)工廠的 優(yōu)缺點(diǎn),比如在什么地方適合使用,什么場合最好不要使用等等。這本書我覺得翻譯的也不錯(cuò),絕對值,強(qiáng)烈向有一定開發(fā)經(jīng)驗(yàn)的人推薦。我大概看了3周半的樣子 把這本書看完,這時(shí)的時(shí)間也到了2004年的9月初,新員工入司培訓(xùn)也不再是第一個(gè)月純粹的日語培訓(xùn),而是技術(shù)培訓(xùn)和日語培訓(xùn)一起開展,技術(shù)上培訓(xùn) Java,Web開發(fā),數(shù)據(jù)庫開發(fā)這三門課程,日語則開始進(jìn)行日本語國際三級的培訓(xùn)。公司的日語培訓(xùn)和技術(shù)培訓(xùn)都還不錯(cuò),技術(shù)培訓(xùn)純粹把大家當(dāng)作什么都不 懂的人,在Java上從最原始的Hello World開始培訓(xùn),Web開發(fā)上從HTML頁面開始培訓(xùn),數(shù)據(jù)庫開發(fā)則從Oracle的安裝,SQL語句的編寫開始培訓(xùn)。當(dāng)然,在培訓(xùn)的過程中我也不會 閑著,而是又開始尋找自己要啃的書本,這次,我選中了Oreilly新出版不久的《Java與XML》第二版。

        由于XML表達(dá)數(shù)據(jù)的自由性以及強(qiáng)大型,所以XML特別適合于做配置文件以及數(shù)據(jù)信息文件,在Java中XML的使用可謂是多如牛毛。在J2EE中,從 Web Application的web.xml開始就是XML文件,到下面的Framework配置等等,沒有一個(gè)沒有XML的身影,而且XML都起到了舉足輕 重的作用。雖然我原來也懂一點(diǎn)XML,不過也僅限于XML的語法以及結(jié)構(gòu)等等,那些深入下去的東西基本還是盲點(diǎn),關(guān)于Java中如何處理XML更是一竅不 通。為了更好的學(xué)習(xí)J2EE,XML是必須征服得一座山峰。這次,我依然又再一次信任了Oreilly出版社,買了本當(dāng)時(shí)出版不久的《Java與XML》 中文第二版。這本書剛開始并沒有過多介紹XML本身過多的東西,只是為了怕某些讀者并不了解XML而對XML語法結(jié)構(gòu)等做了非常簡要的介紹,不過也非常到 位的介紹。介紹完了這些XML基礎(chǔ)知識后就開始了SAX——〉DOM——〉JDOM——〉JAXP——〉Web Service的歷程。不過我現(xiàn)在覺得如果能介紹DOM4J就更好了,因?yàn)槲椰F(xiàn)在覺得DOM4J是Java中最好用而且性能也不錯(cuò)的XML處理工具。剛開 始的我其實(shí)什么是SAX,什么是DOM都不知道,對JAXP更是一無所知。這本書英文版據(jù)說很受好評,中文版我只能說一般,因?yàn)橛行┑胤焦烙?jì)譯者并不擅長 這一塊,所以翻譯得很生硬,以至于部分段落難于理解。總體來說,書的絕大多數(shù)內(nèi)容還是可以看懂,由于沒有具體實(shí)際操作的經(jīng)驗(yàn),所以很多也就是把概念理解 了,直到幾個(gè)月后做正式項(xiàng)目開始應(yīng)用這些XML處理工具進(jìn)行開發(fā)的時(shí)候才達(dá)到了熟練運(yùn)用的能力。在這本書中學(xué)會了JDOM的使用方法,JDOM也還是比較 好用的,學(xué)會了JDOM,以后操縱XML也方便了許多。這本書我的建議就是,可以一口氣讀到第十章JAXP部分,后面的Cocoon以及SOAP等等部分 那本書介紹的并不是很好。Cocoon我是看了官方專門的幫助文檔以后才感覺入了門。而SOAP是經(jīng)過別的書籍加上項(xiàng)目中的實(shí)際運(yùn)用才真正學(xué)會的。

    這 時(shí)到我剛進(jìn)公司已經(jīng)兩個(gè)月過去了,時(shí)間已經(jīng)到了9月中旬的樣子,還有一個(gè)月我們公司新員工入司培訓(xùn)就要結(jié)束,也意味著還有一個(gè)多月我們就要開始接觸正式項(xiàng) 目。這時(shí)的我寫B(tài)/S程序僅僅是JSP + JavaBean的水平,連JSP中的TAG都不會自定義,看見別人網(wǎng)上的程序自己還自己定義Tag很是羨慕,于是決定把那本《JSP設(shè)計(jì)》認(rèn)真看完,把 自定義Tag的功能實(shí)現(xiàn)。后來看了以后發(fā)現(xiàn)原來那本《JSP設(shè)計(jì)》的精華都在最后的150頁內(nèi),最后那部分先是介紹了自定義Tag的定義方法以及Tag定 義所帶來的一些好處。自從學(xué)會了如何自定義Tag,在后來公司的項(xiàng)目中自己也根據(jù)項(xiàng)目的特點(diǎn)定義了一些共通的Tag,大大方便了不少項(xiàng)目中的開發(fā)人員,提 高了生產(chǎn)力。這本書而且也說了一下B/S開發(fā)的兩種Web Module。在這里,我第一次知道了Web開發(fā)可以用一個(gè)Servlet作為控制器,用JSP僅僅作用于表現(xiàn)層,這也為以后掌握MVC打下了很好的基 礎(chǔ)。

    9月中下旬掃完了《JSP設(shè)計(jì)》的尾巴后,有一次跟公司給我們培訓(xùn)的老師在閑聊時(shí)談到了項(xiàng)目開發(fā),我詢問他項(xiàng)目是不是用JSP和 JavaBean來開發(fā),他笑著和我說不是這樣的,而是基于Framework來進(jìn)行開發(fā)。比如Struts就是公司的常用Framework。 Struts這東西以前也好像聽說過,不過從來也只是聽說而已,并沒有看過。得到這個(gè)信息的我,為了能盡快熟悉實(shí)際項(xiàng)目的開發(fā)環(huán)境,便決心盡快學(xué)會 Struts。當(dāng)時(shí)的市場上講解Struts的書只有一本,也就是Oreilly的《Jakarta Struts編程》,不像現(xiàn)在連《Struts in Action》的中文版也有了。我去了書店買來開始回家看,剛開始看的時(shí)候覺得如同云里霧里一般,因?yàn)檫@本書歸納總結(jié)性的東西很多,比較適合當(dāng)參考手冊, 而真正帶領(lǐng)新手入門這一塊做的并不好。所以當(dāng)我把這本書都看完了以后,還是不會用Struts編寫一個(gè)程序,只是感覺自己朦朦朧朧懂了一些概念,比如 MVC什么的。在公司我們的培訓(xùn)也結(jié)束了,通知在國慶節(jié)過來以后的第一個(gè)星期——大概是10月10日左右進(jìn)行考試,最后根據(jù)培訓(xùn)考核情況來調(diào)整薪水。當(dāng)時(shí) 跟我一起培訓(xùn)的新員工基本上沒有人會Struts,其實(shí)這個(gè)時(shí)候連會用JSP + JavaBean寫一個(gè)最簡單的登錄畫面的人也沒有多少個(gè),大部分人還是模模糊糊懂一點(diǎn),但是具體做東西還是做不來的那種水平。國慶節(jié)大概10月5號的我 去了趟書店,突然發(fā)現(xiàn)書架上新上了一本書,就是孫衛(wèi)琴編寫的《精通Struts》這本書。孫衛(wèi)琴的書我倒是聽說過,就是在這之前出的一本關(guān)于Tomcat 以及Web App開發(fā)的書,據(jù)說挺容易上手的。我翻看了這本書的目錄結(jié)構(gòu),覺得可以值得一讀,于是雖然價(jià)格不菲,仍然買回家當(dāng)天就研讀起來。憑我的讀后感覺來說,這 本書也許學(xué)術(shù)價(jià)值并不高,說得深入的東西基本沒有,但是特別適合初學(xué)者,通過Hello World這種例子迅速讓你手把手編寫出第一個(gè)Struts程序。就這樣,在這本書買回來的第二天,我自己就用Struts寫了一個(gè)很簡單的登錄畫面程 序,當(dāng)時(shí)的感覺別提多興奮了,就感覺自己入了門,以后的道路一片光明。在這里,我要由衷地感謝孫衛(wèi)琴女士,寫了這么一本適合初學(xué)者的書,同時(shí)也建議沒有學(xué) 過Struts但又想掌握Struts的Java程序員們買這本書回來看(不知道我是不是有書托之嫌,我只是說我自己的心里想法)。

        國慶的假期放完了,我也回到了公司準(zhǔn)備考核,上午是筆試,下午是上機(jī)考試。筆試分為了4塊,分別是Java,Web開發(fā),Oracle數(shù)據(jù)庫,以及 CMMI規(guī)約。這四門除了Oracle數(shù)據(jù)庫我一向不是很擅長,只考了個(gè)中等分?jǐn)?shù)以外,其他三門分?jǐn)?shù)都名列前茅。不過CMMI規(guī)約老實(shí)說我也不怎么會,不 過碰巧考的很多都是我知道的東西。下午是上機(jī)考試,題目給出來了,我一看題目,原來是一個(gè)最簡易的成績查詢系統(tǒng),也就是數(shù)據(jù)庫里面已經(jīng)有一些學(xué)生成績,我 們寫一個(gè)檢索頁面,可以輸入或者選擇檢索條件,把符合我們檢索條件的數(shù)據(jù)輸出并顯示在畫面中。我于是拿剛學(xué)會不久的Struts進(jìn)行編寫,在3個(gè)小時(shí)內(nèi)把 整個(gè)頁面都寫好了,并且還自定義了一個(gè)Tag來顯示數(shù)據(jù)信息。考完以后我才知道總共也就五六個(gè)人程序可以運(yùn)行,而且只有我一個(gè)人用的是Struts,其他 人基本都是最簡單的JSP + JavaBean,有的人連JavaBean都沒有,數(shù)據(jù)庫操作全部寫在了JSP頁面中。毫無疑問,這次上機(jī)考試我得到了好評,給了最高分。在全部的培訓(xùn) 成績中我也居前兩名,我們部門新員工我排第一名。帶著這個(gè)成績,我們的入司培訓(xùn)基本結(jié)束,開始進(jìn)入部門做實(shí)習(xí)項(xiàng)目。

        雖然說我們正式進(jìn)了部門,不過試用期還沒有結(jié)束,我們試用期最后一個(gè)月的任務(wù)就是做一個(gè)實(shí)習(xí)項(xiàng)目,當(dāng)然,每天還是要進(jìn)行日語培訓(xùn),因?yàn)橐獏⒓?2月份的國 際日語三級考試。公司也象征性得給大家培訓(xùn)了三節(jié)課的技術(shù),第一節(jié)是Struts培訓(xùn),第二節(jié)是Web App的MVC結(jié)構(gòu)的培訓(xùn),第三節(jié)是Log4j培訓(xùn),這幾次培訓(xùn)下來,大部分人感覺好象云里霧里一樣,基本什么都沒聽懂,不過我由于有了點(diǎn)Struts的 基本知識,所以感覺收獲比較大,特別是MVC的培訓(xùn)中我真正明白了視圖——控制器——模型這三層每層應(yīng)該怎么處理,知道了一個(gè)Web App中如何分Java Package比較好,明白了專門有一個(gè)DAO層來處理數(shù)據(jù)庫所帶來的便捷,明白了Log在Web開發(fā)中的重要地位,這為以后的開發(fā)帶來了很大的好處。實(shí) 習(xí)項(xiàng)目的課題很快就下來了,要我們做一個(gè)電子相冊的B/S系統(tǒng),要求有圖片上傳,圖片檢索,圖片顯示以及要用Struts來構(gòu)建,這些是基本的要求,其他 功能可以自由擴(kuò)張。我們部門的新員工分為兩個(gè)小Group,都是一樣的課題,互相促進(jìn)和學(xué)習(xí),每個(gè)Group還配備了一個(gè)老員工,作為督促我們的進(jìn)度,防 止我們有過大的偏差等等,不過具體做東西上原則上要求是不會給我們什么幫助。首先每個(gè)小Group要選出一個(gè)Leader,結(jié)果我被大家一致選為我們 Group的Leader。在小組討論中我們先進(jìn)行需求分析,大家的討論很是熱烈,主意也很多,不過基本上組員們也都是點(diǎn)子多,具體實(shí)現(xiàn)上面還都沒有想 過。對于他們的那些建議,絕大多數(shù)我決定都作為我們要實(shí)現(xiàn)的目標(biāo),但也有少部分我覺得目前以我們的水平還無法實(shí)現(xiàn)的,就先否決了。會議開完后,當(dāng)天回家以 后我就開始排開發(fā)計(jì)劃和個(gè)人的進(jìn)度,第二天寫畫面的基本設(shè)計(jì),第三天把組員拉過來開始Review基本設(shè)計(jì),我們組的速度還算比較快。從星期二公布課題, 到星期五就和幾個(gè)組員一起把DEMO畫面設(shè)計(jì)出來了。原來的計(jì)劃是第二個(gè)星期一開始Coding,大概花一個(gè)星期完成。不過其余組員似乎還是不怎么會 Struts,于是我回家星期六星期天基本全天都在看書寫代碼學(xué)習(xí),花了兩天把項(xiàng)目基本Coding完畢。其中Web頁面部分也不再使用一開始使用 Frame的做法,而是采用了Tiles框架。Tiles的使用過后我感覺是非常好的東西,經(jīng)過簡單的配置可以完成大批網(wǎng)頁中類似部分的構(gòu)建,而且生成的 屬于一個(gè)頁面,這樣就省去了以前寫Frame時(shí)提交頁面總是要考慮設(shè)置Target以及在引用對象的時(shí)候大批Parent或者top對象使用的麻煩事了。 在開發(fā)過程中我使用了Log4j,這為我的調(diào)試程序帶來了極大的方便,呵呵,可以想象,沒有Log來調(diào)試一個(gè)Web程序真是不可想象的。

    這 段時(shí)間我是邊開發(fā)邊翻查那本《精通Struts》的,這樣,迅速把Struts中提供的許多Tag弄熟練了,為以后具體的項(xiàng)目開發(fā)帶來了便捷。也許是一向 以來公司的實(shí)習(xí)項(xiàng)目完成效果都不是很理想吧,這次我們的迅速完成比較出乎Leader的意料,綜合三個(gè)月的試用培訓(xùn),由于我在日語和技術(shù)以及實(shí)習(xí)項(xiàng)目中表 現(xiàn)都還不錯(cuò),所以定工資級別時(shí)也是同一批進(jìn)公司的新員工中最高的,隨著轉(zhuǎn)正會議的結(jié)束,我也在10月底成為了公司的正式員工。大概剛剛進(jìn)入11月份,我們 Group便開動一個(gè)項(xiàng)目,項(xiàng)目不是很大。當(dāng)時(shí)老員工們許多都在做項(xiàng)目的詳細(xì)設(shè)計(jì),我便跟著公司一位技術(shù)專家(也是當(dāng)初給我們?nèi)胨九嘤?xùn)的其中一位老師)做 起項(xiàng)目的Framework構(gòu)建工作。當(dāng)時(shí)的我才進(jìn)公司,第一資歷尚淺,第二我的確也并不是很會什么東西,所以給我的任務(wù)很多都是一些模塊的 Utility的設(shè)計(jì)。比如通用的Check方法啊,CSV以及定長文件的讀取解析什么的啊,還有某些在IE中可以實(shí)現(xiàn)的效果如何在Netscape中也 能實(shí)現(xiàn)同樣的效果等等。雖然這些東西在現(xiàn)在看來并不是很復(fù)雜,但是當(dāng)時(shí)自己的確隨著做這些東西而學(xué)到了很多很多。比如使用JDOM對XML文件的解析啊, 很多Check方法的小技巧啊,IE和Netscape究竟有什么地方不一致,該如何解決等等,這些都在這幾天內(nèi)了解了很多。在這幾天中,我通過網(wǎng)上查找 資料,臨場迅速學(xué)習(xí)了Java反射的使用方法,并且自己邊學(xué)邊寫實(shí)例,實(shí)現(xiàn)了各種情況下的反射案例。我個(gè)人覺得掌握J(rèn)ava反射技術(shù)是非常重要的,這讓你 可以寫一些通用的工具。如果不會反射技術(shù)的話,也許你永遠(yuǎn)只能寫一些針對特定情況下的解決方法。而會使用反射以后,你可以寫一些代碼,這些代碼可以用在許 多地方,達(dá)到自己擴(kuò)展甚至構(gòu)建Framework的效果。在這個(gè)項(xiàng)目中,我使用了自定義Tag和Java反射技術(shù),定義了些項(xiàng)目中比較需要的通用的 Tag,方便了大家。

        后來聽老員工說新員工進(jìn)公司就開始做Framework是以前從來都沒有過的事情,因?yàn)槲覀僉eader對我希望比較大,所以想盡可能培養(yǎng)我,讓我早點(diǎn)挑 起項(xiàng)目大梁,所以給我的成長提供了一次又一次的機(jī)遇。11月中旬以后,項(xiàng)目開始進(jìn)入編碼階段,我也第一次看到了正式的項(xiàng)目設(shè)計(jì)書。第一次看到設(shè)計(jì)書的時(shí)候 我都覺得自己腦子有點(diǎn)懵,一大堆日語什么含義自己不是很清楚,而且感覺根本無從下手,不知道從哪里開始看比較好。項(xiàng)目擔(dān)當(dāng)耐心得和我說了設(shè)計(jì)書的格式以及 究竟什么地方是什么一個(gè)含義,以及Coding的時(shí)候按照什么個(gè)思路來看設(shè)計(jì)書。再加上項(xiàng)目中有老員工先寫了個(gè)Sample,讓大家看了標(biāo)準(zhǔn)的一個(gè)流程, 所以我們就依葫蘆畫瓢,慢慢得把一個(gè)畫面一個(gè)畫面Coding完畢。當(dāng)然了,后來也有測試員來測試我們的畫面,發(fā)現(xiàn)bug后就發(fā)Bug Report給我,那一個(gè)月就是在Coding,修正Bug中渡過的,這個(gè)項(xiàng)目是用Struts做的,因?yàn)椴淮蟆K砸矝]有再用其他的 Framework,數(shù)據(jù)庫操作那里只有個(gè)非常簡單的單表操作DAO層,其余的DB操作都是自己通過JDBC操作語句來完成的。在這第一個(gè)自己接觸的真正 項(xiàng)目中,我自己學(xué)到了很多B/S設(shè)計(jì)的技巧,感覺很充實(shí)。不過書本學(xué)習(xí)方面我也沒有閑著,我為了能夠深入了解Java,大概在11月中旬左右開始看《深入 Java虛擬機(jī)》這本書,由于內(nèi)容比較深入,所以看得也有點(diǎn)吃力。書翻譯得和寫得都還不錯(cuò),值得一看,我一直看了前八章,看到Java程序運(yùn)行細(xì)節(jié)后就沒 再看了,大概看到了12月底的樣子吧,呵呵,有時(shí)間的話決定把后面的部分也看完。這本書看完后收獲就是了解了Class文件的實(shí)質(zhì),Java的安全模型, 虛擬機(jī)是如何工作的。這些知識對后來調(diào)試程序Bug或者Exception的時(shí)候非常有好處,可以把以前自己覺得莫名其妙的錯(cuò)誤的原因找出來,不像以前遇 到很古怪的Exception的時(shí)候怎么死的都不知道,從讀完這本書以后,在以后的調(diào)試異常中很少再有不知所以然的感覺了。

        2004年12月底的時(shí)候,我的第一個(gè)項(xiàng)目也做完了,由于我空閑著,Leader便在星期三的時(shí)候把一個(gè)公司內(nèi)部開發(fā)的Source統(tǒng)計(jì)的小工具讓我進(jìn)行 修改,使得添加一個(gè)比較有用的功能。東西給我的時(shí)候基本沒有任何文檔,在我手上的就是一堆源代碼而已,界面是用Swing制作的,因?yàn)闆]有專門在UI上進(jìn) 行精心設(shè)計(jì),所以說不上好看,典型的Java編寫的圖形界面的程序的樣子。軟件不是非常大,估計(jì)在1萬行源代碼以內(nèi),不過對于只有一個(gè)人修改來說,也比較 夠嗆了。還好我在剛學(xué)Java的時(shí)候用JBuilder寫了一些Swing的程序,現(xiàn)在還是對Swing有概念的,所以拿到手上以后經(jīng)過仔細(xì)分析,逐漸理 清了頭緒。經(jīng)過修改和自己測試完畢后,覺得還比較滿意,達(dá)到了預(yù)期的目標(biāo),于是在星期五的時(shí)候提交給了Leader。通過這次,對Swing的開發(fā)又加深 了印象,自然,在有的細(xì)節(jié)技巧方面受益匪淺。

    元旦很快來臨了,在年底以前,公司覺得有必要學(xué)習(xí)下Hibernate,雖然我們目前的項(xiàng)目中 還沒有用過Hibernate,而是用另外一個(gè)公司內(nèi)部開發(fā)的ORM工具,不過幾名技術(shù)專家初步對Hibernate感覺后覺得Hibernate的功能 要強(qiáng)大的多,而且是開源的,不斷有人在推動,升級,所以有必要我們要學(xué)Hibernate。這次的學(xué)習(xí)采用學(xué)習(xí)小組的形式,也就是公司內(nèi)部先抽幾名員工 (主要是技術(shù)部門的,當(dāng)然,開發(fā)部門如果有興趣的話也可以考慮)來進(jìn)行深入學(xué)習(xí),然后定期開會交流互相學(xué)習(xí),達(dá)到短時(shí)間內(nèi)先行的幾名成員迅速深入掌握 Hibernate的形式。由于我第一處于空閑狀態(tài),第二也比較有興趣,而且跟技術(shù)部門的專家們也比較談得來,所以我也加入了其中,成為幾名學(xué)習(xí)小組中成 員的一部分。我們學(xué)習(xí)資料主要就是《Hibernate in Action》英文版一書以及官方的幫助手冊。我負(fù)責(zé)其中對象操作,Transaction和Cache,還有高級Mapping關(guān)系的設(shè)置幾個(gè)部分的學(xué) 習(xí)。由于資料都是全英文的,所以看書速度并不是很快,不過還是初步得到掌握了。大概學(xué)習(xí)了半個(gè)多月的樣子,我們各自基本學(xué)習(xí)完畢,互相交流后并且寫下了讀 書筆記,用來后面具體項(xiàng)目開發(fā)時(shí)候參考用。通過這大半個(gè)月的學(xué)習(xí),我個(gè)人覺得提高了非常多,在這之前,我只知道有ORM這種東西,但是從來沒有使用過,也 從來沒有看過。自從學(xué)過了以后,我不僅對Hibernate在代碼編寫時(shí)的使用比較熟悉了,而且對Hibernate的配置以及許多底層的知識有了很清楚 的認(rèn)識,讓自己在數(shù)據(jù)持久化方面的認(rèn)識提高了大大的一步。

        元旦過后,雖然一邊在學(xué)習(xí)Hibernate,不過由于下面項(xiàng)目的需要,Leader跟我說要我學(xué)一下Unix下的Shell編程,因?yàn)? 項(xiàng)目中許多批處理會用Shell來啟動。UNIX命令在學(xué)校時(shí)候?qū)W過的,不過這個(gè)時(shí)候已經(jīng)忘記了很多,只是翻閱資料的時(shí)候還能回想起來不少命令。 Shell并不難,如果有了編程基礎(chǔ),學(xué)習(xí)Shell編程也很快的,總體感覺就是編程語言大同小異,從基本語法來說,不外乎賦值、條件、循環(huán)這幾種類型。 只要迅速掌握這幾種類型在這種編程語言中的編碼格式,那么你就可以迅速掌握這門語言最基本的編程能力。Shell經(jīng)過一周的學(xué)習(xí)后覺得感覺不錯(cuò),不僅可以 順利看懂別人寫的Shell程序,而且自己可以在Linux下順利寫出符合自己需求的Shell程序并能順利執(zhí)行。但是突發(fā)事件總是有的,那個(gè)項(xiàng)目突然決 定延后兩個(gè)月,所以前一個(gè)星期的學(xué)得Shell等于暫時(shí)派不上用場了。不過嘛,多學(xué)一樣技能總是沒有害處的,而且又復(fù)習(xí)了那么多Unix命令啦,感覺還是 很不錯(cuò)的。于是我又進(jìn)入了不在項(xiàng)目中的真空期了。

        但是好景不長啊,好日子還沒有過上兩個(gè)星期,公司去年做的一個(gè)比較大的項(xiàng)目開始了2期開發(fā),我也被一下拖入了項(xiàng)目中。說起那個(gè)項(xiàng)目,公司好多人還心有余 悸,據(jù)說去年那個(gè)項(xiàng)目開發(fā)的時(shí)候,大概50多號人干了好幾個(gè)月,每天都是11點(diǎn)以后才有可能回家,周六是鐵定加班,周日是看情況,晚上就算加班加到凌晨3 點(diǎn)也不是什么奇怪的事情。當(dāng)時(shí)大家都說多來幾個(gè)這種項(xiàng)目大家就要死了,這次這個(gè)項(xiàng)目的2期過來了,大家精神又一次緊張起來咯。一開始照例是項(xiàng)目會議,聽完 項(xiàng)目經(jīng)理描述以后,大家也放心了不少,這次雖然說是二期,不過規(guī)模不大,只需要15個(gè)人左右干一個(gè)月就能搞定。主要是把項(xiàng)目一期里面一些地方進(jìn)行改修,當(dāng) 然也有需要新的畫面的開發(fā),不過相對于去年的那塊不是很多而已。對我來說這次是個(gè)很大的考驗(yàn),因?yàn)轫?xiàng)目是二期,項(xiàng)目組內(nèi)除了我,其他的人都做過1期開發(fā), 所以對項(xiàng)目結(jié)構(gòu)都很清楚。這次項(xiàng)目開始并沒有什么培訓(xùn),所以我只能單獨(dú)看1期的源代碼來熟悉項(xiàng)目結(jié)構(gòu)什么的。這個(gè)時(shí)候項(xiàng)目經(jīng)理把我叫去要我辦理護(hù)照,準(zhǔn)備 這個(gè)項(xiàng)目派遣我去東京現(xiàn)場維護(hù)。

    這個(gè)項(xiàng)目是個(gè)比較全面比較大的項(xiàng)目,服務(wù)器采取了集群的方式,數(shù)據(jù)量也是千萬乃至上億級別的,所以性能要求 特別高。在技術(shù)方面用到了很多,使用EJB來控制Transaction,使用了ORM工具來操縱DB數(shù)據(jù)等等等等。而且由于比較龐大,所以服務(wù)器初始化 的那塊為了Load上去大批配置信息,代碼量極其龐大,在權(quán)限控制的那塊地方,代碼非常難以讀懂。這也給我一開始的學(xué)習(xí)代碼帶來了很大的一塊麻煩。不過總 算靜下心來后把整個(gè)項(xiàng)目框架以及實(shí)現(xiàn)手法基本摸清楚了,這個(gè)時(shí)候覺得非常開心,而且對Web應(yīng)用程序的構(gòu)造心里面也非常充實(shí),覺得自己已經(jīng)具備寫 Framework的初步能力了。

    項(xiàng)目是緊張的,基本上每天晚上都要加班到11點(diǎn),然后打車回家,哈哈,公司報(bào)銷。而且臨近過年,這么加班 也一點(diǎn)都感覺不到過年的氣息。不過我也不能因此放松了自己的學(xué)習(xí)。我覺得自己的基礎(chǔ)應(yīng)該算比較好了,便開始啃起另外一本大部頭——《Java與模式》。一 直以來我對設(shè)計(jì)模式的感覺就是一些已經(jīng)成型的,久經(jīng)考驗(yàn)的代碼框架,具有非常好的可擴(kuò)展能力以及非常好的代碼健壯性。不過初學(xué)者最好不要看設(shè)計(jì)模式,因?yàn)? 你接觸的代碼不多,如果貿(mào)然看設(shè)計(jì)模式的話,會造成不明白為什么這種設(shè)計(jì)模式好,究竟好在什么地方的情況下就在代碼中亂套設(shè)計(jì)模式,對自己的以后編碼發(fā)展 帶來不利的影響。每一種設(shè)計(jì)模式都有每一種設(shè)計(jì)模式的特點(diǎn),自然也有他們自身的適用范圍,比如拿最基本的單例模式(Singleton)來說,適合于做配 置信息讀取器,主鍵產(chǎn)生器等全局唯一的東西。如果初學(xué)者不明白這些,拿單例模式亂套,什么都用單例模式,比如把普通傳遞數(shù)據(jù)用的JavaBean也做成了 單例模式,帶來的惡果就嚴(yán)重了。這本《Java與模式》我是從頭到尾認(rèn)認(rèn)真真看了,每看完一個(gè)模式都會仔細(xì)回想以前看的代碼哪里用到過這個(gè)模式,總會自己 想想這些模式適用于哪些地方。因?yàn)檫@個(gè)時(shí)候我自己編寫的代碼行數(shù)也已經(jīng)很多了,所以看見這些模式就會特別有感覺。經(jīng)過50多天的認(rèn)真研讀,所有模式都被我 消化了下去,并且使得我的對程序開發(fā)上面的認(rèn)識提升了非常大的一步。順路說一句,這本書寫得非常好,例子很多,但是不復(fù)雜,有一定代碼編寫經(jīng)驗(yàn)的人就可以 看懂了。不過看懂并不是最重要的,重要的是消化下去,用來理解以前看過的代碼的精華,這樣自己才能得到提高。

        這個(gè)項(xiàng)目雖然很緊張很忙,不過我還是適應(yīng)了下來,而且對整個(gè)項(xiàng)目結(jié)構(gòu)什么的都有了比較好的整體的把握。項(xiàng)目橫跨了整個(gè)過年期間,所以在過年的那幾天都必須 開著手機(jī),怕有什么突發(fā)事件要求去加班。簽證在2月4日左右送過去簽,Leader跟我說因?yàn)樵谶^年期間,所以簽證可能會比較緩慢,比較難簽,不過一般情 況下1個(gè)月應(yīng)該足夠了。原計(jì)劃我是跟另外兩個(gè)同事3月6日去東京,這樣算算也差不多。不過中國有句話叫好事多磨,呵呵,用在我身上的確不過分,我的簽證3 月3日日本領(lǐng)事館才簽,三月四日送到南京。3月5日和3月6日是雙休日,所以3月7日簽證才送到我手上。由于計(jì)劃是3月6日派人去東京,所以只好派另外一 個(gè)身上有簽證還沒有過期的人代替我過去,這次的機(jī)會就算泡湯咯。不過我并不是很在意,因?yàn)楣具@里去東京出差的機(jī)會狠多,特別對于開發(fā)人員,據(jù)說工作幾年 后一聽到去日本出差就不樂意,畢竟也背井離鄉(xiāng)么。

        在這個(gè)項(xiàng)目的途中,大概在2005年1月底2月初的時(shí)候公司也開始進(jìn)行了制作詳細(xì)設(shè)計(jì)的培訓(xùn),我雖然在項(xiàng)目中,不過也成為了其中一員。這次培訓(xùn)總共大概6 次課,每次2個(gè)多小時(shí),雖然時(shí)間不長,不過把詳細(xì)設(shè)計(jì)的要點(diǎn)以及思路和容易出錯(cuò)的地方都說了出來,感覺很是不錯(cuò),這幾次課的培訓(xùn)后,雖然可能要我立即進(jìn)行 詳細(xì)設(shè)計(jì)編寫還有點(diǎn)困難,不過心里面已經(jīng)有了不少底,我覺得經(jīng)過一段時(shí)間后的鍛煉,我應(yīng)該可以有進(jìn)行詳細(xì)設(shè)計(jì)的能力了。

        3月初這個(gè)大項(xiàng)目結(jié)束后,本以為可以休整下,不過很快通知我3月7日加入另外一個(gè)項(xiàng)目,其實(shí)也不算一個(gè)正式的項(xiàng)目,屬于公司知識庫的一個(gè)信息查詢模塊。由 公司的一個(gè)技術(shù)專家負(fù)責(zé),那人也就是我進(jìn)公司時(shí)候第一個(gè)項(xiàng)目中帶著我的那個(gè)技術(shù)專家,說起來我和他還真有緣,現(xiàn)在我這個(gè)項(xiàng)目還是跟著他,而且公司里面唯一 一個(gè)和我同月同日生的人,真是很巧的巧合呢。他人挺好,很熱心,所以我也從他那學(xué)到了很多東西。這次由于不是正式項(xiàng)目,所以并沒有什么基本設(shè)計(jì)書,而是他 給我們開會議的時(shí)候大致說了下項(xiàng)目的內(nèi)容,每個(gè)畫面的具體功能以及數(shù)據(jù)庫表格的設(shè)計(jì)。由于這次項(xiàng)目規(guī)模很小,總共就12個(gè)畫面的量,所以不采取 Struts等Framework,而是采用比較原始的JSP + JavaBeans的構(gòu)造。我們每個(gè)人根據(jù)他所跟我們講解得功能寫每個(gè)人自己分配到的畫面的詳細(xì)設(shè)計(jì),其實(shí)也不算真正的詳細(xì)設(shè)計(jì),就是每個(gè)人把自己操作的 那塊的具體邏輯設(shè)計(jì)寫出來,然后和他一起review一次,再開始編寫代碼。詳細(xì)設(shè)計(jì)這里我做的很快,當(dāng)天下午就把自己分配到的兩個(gè)畫面業(yè)務(wù)邏輯什么的都 寫好了,星期一布置得任務(wù),我星期三的時(shí)候全部編碼自測完畢提交,所以我的感覺就好像這個(gè)小項(xiàng)目一瞬間就結(jié)束了。

    日本每年財(cái)務(wù)結(jié)算是在3月 份,所以我們歷來的習(xí)慣就是每年1月和2月很忙,3月開始清閑,一直可以到5月左右會接到個(gè)大項(xiàng)目昨。所以接下來就真正到了我的空閑時(shí)期,沒有項(xiàng)目的壓 力,我可以自由學(xué)我自己喜歡的東西。很久以前買了本《精通EJB》第二版,可是一直以來我覺得自己功力尚淺,所以沒有看,這次我想認(rèn)真學(xué)學(xué)EJB。雖然大 家公認(rèn)EJB并不是很好,不過歷來受到批評的都是EJB中的Entity Bean部分,這部分我覺得可以借助Hibernate來彌補(bǔ),而會話Bean和消息驅(qū)動Bean則還是挺不錯(cuò)的。這次也當(dāng)學(xué)一門技術(shù),學(xué)習(xí)其好的東西, 不是很好的東西就當(dāng)作以后開發(fā)時(shí)候的借鑒。《精通EJB》這本書我的感覺是書質(zhì)量比較好,不過翻譯的水平稍微差了點(diǎn),特別是有不少錯(cuò)誤,而且很低級的錯(cuò)誤 居然校對的時(shí)候都沒有發(fā)現(xiàn),不能不說是個(gè)比較大的瑕疵。但是它不失為一本EJB的好教材。從一開始的JNDI開始,然后講解了對象序列化,RMI- IIOP等等。這些以前都模模糊糊,或者是看過了但是還不知道究竟有什么用。但是經(jīng)過這次的學(xué)習(xí)以后,對這些分布式系統(tǒng)比較需要的東西有了進(jìn)一步的了解, 感覺頭腦中比較清晰,究竟RMI是什么樣的工作原理,怎樣實(shí)現(xiàn)一個(gè)遠(yuǎn)程方法調(diào)用等等。接下來的EJB學(xué)習(xí),自己用Eclipse + Weblogic邊看書邊動手,寫了一個(gè)個(gè)自己的學(xué)習(xí)小程序。我個(gè)人感覺看書最好就是邊看邊自己動手寫小學(xué)習(xí)程序,這樣比光看不練能學(xué)到多得多的東西。學(xué) 了EJB后覺得腦子又清晰了很多,看見一個(gè)案例后頭腦中就會有好幾種如何解決的方法,幾種方法互相在頭腦中自己比較,經(jīng)過這樣,大大提高了自己的思維活躍 性。

        3月中旬開始由于公司比較清閑,大部分人處于沒有項(xiàng)目的狀態(tài),所以公司舉辦了第一屆全公司范圍的編程競賽。公司只指定了題目為一個(gè)日歷系統(tǒng),要求具有日程 記事等功能,其余功能自由發(fā)揮。這次不再采用團(tuán)隊(duì)形式了,而是采取各自為戰(zhàn)的策略。自從培訓(xùn)過詳細(xì)設(shè)計(jì)以后,我頭腦一直有如何寫詳細(xì)設(shè)計(jì)的思路,這次我自 己首先指定了開發(fā)計(jì)劃,保證自己控制自己的進(jìn)度。接著進(jìn)行了需求分析,確定了我有哪些功能。然后在自己的基本設(shè)計(jì)中開始進(jìn)行數(shù)據(jù)庫結(jié)構(gòu)設(shè)計(jì)。這次我決定采 用Hibernate+Struts的結(jié)構(gòu)進(jìn)行編寫,這樣我的數(shù)據(jù)持久層操作大大簡化,而且功能上也增強(qiáng)了許多。DB設(shè)計(jì)好以后我開始DEMO畫面的制 作。說實(shí)話,我美工水平實(shí)在不怎么樣,可以說雖然一般網(wǎng)頁的效果我都會自己做出來,不過具體網(wǎng)頁設(shè)計(jì)成什么樣我還真是一竅不通。還好 Dreamweaver我還算算是比較熟練,自己搗鼓搗鼓也想摸象樣把DEMO畫面給設(shè)計(jì)出來了,不過美觀不美觀我就覺得不怎么樣了,只是我能力有限,也 沒辦法設(shè)計(jì)的更好看,這個(gè)時(shí)候我感受到了一個(gè)項(xiàng)目中美工是多么重要啊。下面的詳細(xì)設(shè)計(jì)自己寫得很開心,把需要的功能都用文字反映了出來,這也算我寫成詳細(xì) 設(shè)計(jì)樣子的第一份詳細(xì)設(shè)計(jì)了,做完挺有成就感的。接下來首先構(gòu)筑自己這個(gè)小項(xiàng)目的Framework,經(jīng)過公司兩個(gè)正式項(xiàng)目的洗禮后,那兩個(gè)項(xiàng)目的 Framework我都認(rèn)真研讀過源代碼的,所以我自己有了自己心里一套Framework的構(gòu)造方法,特別是如何把Struts和Hibernate結(jié) 合起來的結(jié)構(gòu),自己有自己的一些想法。在這次Framework構(gòu)造中,我沒有復(fù)制任何公司以前的代碼段,都是憑著自己對以前看的代碼理解后寫出來的。這 次項(xiàng)目我覺得對自己的提高也很大,首先鍛煉了自己詳細(xì)設(shè)計(jì)的能力。其次,自己雖然學(xué)習(xí)過Hibernate,不過從來沒有這么樣應(yīng)用過 Hibernate,這次讓自己大大提升了實(shí)踐運(yùn)用的經(jīng)驗(yàn)。公司由于知道這時(shí)也沒有一個(gè)真正的項(xiàng)目使用Hibernate,所以這時(shí)的我也算公司內(nèi)部 Hibernate使用經(jīng)驗(yàn)最豐富的人了,這也為了后來我協(xié)助別的使用了Hibernate的項(xiàng)目解決問題的原因。再次,我這次自己寫了 Framework,特別在批處理方面,運(yùn)用了許多剛學(xué)會理解掉的設(shè)計(jì)模式,這些模式讓我的程序更具有健壯性和可擴(kuò)展性,讓我在設(shè)計(jì)方面的能力大大提升 了。

    這次的編程競賽我寫得比較認(rèn)真,代碼量的確也很大,總代碼行數(shù)超過了3萬行,有效代碼行數(shù)也在1萬行以上。經(jīng)過公司專家們的評定后,我 得到了第一名,雖然沒有什么獎(jiǎng)品,不過肯定了我這段時(shí)間以來的努力,我還是很開心的。而且這次的編程競賽讓我大大增加了編碼的熟練度,而且也在其中演練了 許多自己想出來的編程技巧,為以后的發(fā)展帶來很大的好處。

        從4月份開始,公司由于比較清閑,所以部門內(nèi)部開始進(jìn)行各種培訓(xùn)。我們部門開展了3項(xiàng)培訓(xùn),第一項(xiàng)就是編程能力培訓(xùn),第二項(xiàng)是Oracle數(shù)據(jù)庫技術(shù)培 訓(xùn),第三項(xiàng)是測試技巧培訓(xùn)。在編程能力培訓(xùn)中,主要就是把原來沒有注意的細(xì)節(jié)采取大家討論,輪流講課的方式進(jìn)行的,雖然其中很多東西我原來都是知道的,不 過也有原來不清楚的地方。而且經(jīng)過了這次互相討論,更加加深了印象。在Oracle培訓(xùn)中我覺得收獲很大,這個(gè)Oracle培訓(xùn)采取了傳統(tǒng)的上課的模式, 由我們開發(fā)小組中一個(gè)取得OCM的老員工給我們講解。對于Oracle,我原來基本上就只會寫寫SQL語句,具體Oracle有什么特別的功能,可以做什 么我也不是很清楚。但是這次上課從Oracle的啟動原理開始,讓我知道Oracle中究竟有什么,Oracle數(shù)據(jù)庫各部分在磁盤上是如何存放的, Control File,Redo File究竟是什么意思,在數(shù)據(jù)庫中起什么作用,數(shù)據(jù)庫是怎么依賴他們運(yùn)行的,還有如何對Oracle進(jìn)行系統(tǒng)管理員級別的管理,如何在不停止數(shù)據(jù)庫運(yùn)行 的情況下進(jìn)行數(shù)據(jù)庫的更新、升級、備份等等。這些東西雖然非常有用,但在平時(shí)的開發(fā)是學(xué)不到的,這次趁著這個(gè)機(jī)會大大提升了自己Oracle的水平,感覺 非常開心。數(shù)據(jù)庫一向是我的弱項(xiàng),在上大學(xué)的時(shí)候我SQL語句能力只是一般,數(shù)據(jù)庫管理配置什么基本一點(diǎn)都不懂,通過這次集中的培訓(xùn),我覺得自己的能力又 進(jìn)一步增強(qiáng)了,弱項(xiàng)也在慢慢退卻。在三項(xiàng)培訓(xùn)中最后進(jìn)行的測試培訓(xùn)我承認(rèn)我沒有怎么認(rèn)真去學(xué),所以學(xué)會的也就是些測試概念,具體的測試技巧什么的還是不怎 么會。現(xiàn)在開發(fā)和測試的結(jié)合性越來越高,看來要下下功夫,以免給淘汰咯。

        提了這段時(shí)間在公司的進(jìn)展,還沒說自己的學(xué)習(xí)呢,這段時(shí)間正好看見中文版的《JUnit in Action》出版了,在書的背后寫著“如果沒有看過這本書,就不要對J2EE進(jìn)行單元測試”這句話。我早在去年就了解了JUnit的強(qiáng)大功能,再加上 Ant的話對于回歸測試是非常便利的。趁有時(shí)間,我便于3月底4月初的時(shí)候開始看這本書。當(dāng)時(shí)的我看《精通EJB》第二版看了一半,發(fā)現(xiàn)其中錯(cuò)誤越來越 多,而且文字也有些地方不知所云了,所以扔下不再浪費(fèi)時(shí)間看那本書,專心攻讀《JUnit In Action》。憑良心說,Manning的這套In Action叢書的確很不錯(cuò),從我先前看的《Hibernate In Action》英文版就能看出來,其中對代碼的編排非常方便讀者,感覺可以很順利的看到你所想看到的代碼片斷。這套《JUnit In Action》也是一樣,博文視點(diǎn)的紙張還是很好的,排版使用了Manning的風(fēng)格,閱讀起來很舒服,所以我讀得很快,大概就兩個(gè)多星期就讀完了這本 400多頁的書。感覺的確收獲不淺,首先,原來的自動化配置工具中只會使用一個(gè)Ant,其他的基本沒聽說過,在這本書上詳細(xì)介紹了Maven。聽過書中的 講解以及自己的試驗(yàn),的確覺得Maven功能很強(qiáng)大,不過感覺起來配置比Ant要麻煩,所以我自己的感覺是Ant在項(xiàng)目中還是會廣泛應(yīng)用,不過Maven 在大型項(xiàng)目,特別是整個(gè)Site中有很大的用武之地,對于我們來說,使用的方法都是很簡單的,掌握如何編寫配置文件才是我們的關(guān)鍵。

    書對 JUnit與Cactus在J2EE的測試手法上給了大量的事例,給人的感覺非常好,In Action這套叢書最大的優(yōu)點(diǎn)就在這里,用實(shí)例代碼片斷讓你迅速了解一樣?xùn)|西。在實(shí)際工作中其實(shí)JUnit應(yīng)用也是比較廣泛的,特別如果采取測試驅(qū)動開 發(fā)的話,JUnit是必不可少的一部分。在TagLib測試,JSP單體測試,數(shù)據(jù)庫測試和EJB測試都是我以前根本沒有看過的東西。其實(shí)這次雖然學(xué)是學(xué) 會了,不過真正做的時(shí)候還是要有個(gè)代碼例子依葫蘆畫瓢。我想大家肯定也都有這種感覺,寫程序的時(shí)候先找一段有點(diǎn)相似的代碼片斷Copy過來,然后看看要修 改什么地方,真正從頭到尾自己用手寫的代碼片斷是不多的,除非你已經(jīng)爛熟于心。不過這本書快看完的時(shí)候,項(xiàng)目又來了。

        這次做一個(gè)企業(yè)的MIS系統(tǒng),與以往不同的是,這次客戶給了一個(gè)比較龐大的基盤,封裝了近100個(gè)Tag,基本上把各種各樣有可能遇到的操作都封裝到 Tag里面了。而且所有的畫面顯示等信息都是放在數(shù)據(jù)庫的Table中,所以這次要求不寫任何程序代碼,只是學(xué)會使用好這些Tag,然后利用這些Tag寫 出Jsp頁面。一開始的時(shí)候還真是頭疼,這些Tag一個(gè)都不明白,而且文檔不是非常齊全,Tag的Source中注釋也比較少,學(xué)習(xí)起來不是很方便。我們 一共3個(gè)人投入到這個(gè)項(xiàng)目的前期準(zhǔn)備中,在第一個(gè)星期的學(xué)習(xí)中大家互相分配好個(gè)人學(xué)習(xí)的模塊,隨時(shí)互相交流。在后來的深入中發(fā)現(xiàn)這個(gè)項(xiàng)目的業(yè)務(wù)邏輯操作會 使用PL/SQL以及存儲過程來進(jìn)行,對于我來說,PL/SQL是從來沒有做過的東西,就叫做一竅不通,于是我需要從頭開始學(xué)習(xí)PL/SQL,以及如何編 寫存儲過程。我從網(wǎng)上下了一個(gè)PL/SQL的電子書籍,然后在公司花了一天時(shí)間進(jìn)行學(xué)習(xí),個(gè)人用的是Toad來調(diào)試PL/SQL的,雖然別人喜歡用 PL/SQL Developer來進(jìn)行開發(fā),不過我還是比較鐘愛Toad,而且Toad的確功能也很強(qiáng)大,使用起來也很方便就是了。經(jīng)過第一天的PL/SQL的學(xué)習(xí), 基本掌握了全部語法以及存儲過程的書寫格式等等,開始能夠?qū)憣懛浅:唵蔚腜L/SQL。接下來的兩三天不斷鞏固熟練,客戶那里也發(fā)過來幾本詳細(xì)設(shè)計(jì)讓我們 練習(xí)著做一下。有了實(shí)際的詳細(xì)設(shè)計(jì),再加上我們之間互相交流,我們提高的都很快,大概過了三四天,大家就把基本詳細(xì)設(shè)計(jì)代碼編寫完畢了,而且經(jīng)過實(shí)際鍛 煉,我的PL/SQL編寫存儲過程的水平也大大提升,已經(jīng)可以滿足開發(fā)中的需要了。

    這個(gè)項(xiàng)目因?yàn)槿绻覀円婚_始做的能讓客戶滿意的話,后續(xù) 的項(xiàng)目將會比較龐大,所以Leader決定把我們Group比較空閑的其他人也先培訓(xùn)一下,讓他們有點(diǎn)感覺,到以后正式開發(fā)的時(shí)候也能迅速進(jìn)入狀態(tài),負(fù)責(zé) 給他們培訓(xùn)的任務(wù)也就交給了我。說起來是培訓(xùn),其實(shí)也就是把大概流程以及方法通過一次會議的形式告訴他們,然后把我前面已經(jīng)作好的那個(gè)畫面作為他們的作 業(yè),要他們看著設(shè)計(jì)書自己把畫面制作出來。這個(gè)時(shí)候也要放勞動節(jié)了,黃金周可以休息一個(gè)星期,想想就覺得很Happy。勞動節(jié)的時(shí)候基本沒有怎么學(xué)習(xí),只 是先把XML-RPC仔細(xì)看了下,學(xué)會了如何去寫一個(gè)XML-RPC的應(yīng)用,接著稍微看了點(diǎn)SOAP,看得也不錯(cuò),只是些簡單的SOAP的例子而已,那些 SOAP的復(fù)雜東西都沒有看。

        很快就五一黃金周七天放假放完,八號開始上班,上班后就開始正式做節(jié)前就定好的那個(gè)項(xiàng)目,這次性質(zhì)屬于試做,也就是人家先發(fā)一批設(shè)計(jì)書過來,我們?nèi)缓箝_始 Coding,大概做了一周后,我自己害了急性結(jié)膜炎,只能回家休息,這次可真的是只能休息了,眼睛覺得特別漲,不要說電腦了,連書都不能看,看了眼睛就 疼。所以在家就只能睡大覺,過了一周眼睛大概才復(fù)原,可以去公司上班了。回到公司以后,Leader通知我說我不用去做上次那個(gè)項(xiàng)目了,要我加入我們 Group的一個(gè)新的項(xiàng)目,這個(gè)項(xiàng)目比較大,當(dāng)時(shí)還處于東京剛剛做好基本設(shè)計(jì),我們從東京把任務(wù)接下來,準(zhǔn)備發(fā)回來做詳細(xì)設(shè)計(jì)。我進(jìn)去的時(shí)候項(xiàng)目才開始三 四天,基本上還沒有做什么,這次我進(jìn)入了詳細(xì)設(shè)計(jì)制作小組,開始進(jìn)行這個(gè)項(xiàng)目的詳細(xì)設(shè)計(jì)的制作。

        由于我屬于第一次在正式的項(xiàng)目中參與詳細(xì)設(shè)計(jì),所以很多東西都不明白,特別是業(yè)務(wù)上面的東西,許多日語中的業(yè)務(wù)術(shù)語我根本不明白,比如什么賣切,切替,仕 入什么的。看著基本設(shè)計(jì)書,感覺跟以前看詳細(xì)設(shè)計(jì)書有很大的不同。具體的東西寫的少了,業(yè)務(wù)流程邏輯框架什么的比較多,所以需要首先把業(yè)務(wù)內(nèi)容都熟悉了, 才可能寫出詳細(xì)設(shè)計(jì)來。這次的詳細(xì)設(shè)計(jì)我也不是孤軍奮戰(zhàn),而是有一個(gè)進(jìn)公司4年的老員工帶著我一起做,我的任務(wù)很輕,不過重點(diǎn)是學(xué)會如何去寫詳細(xì)設(shè)計(jì),也 許下次再有一個(gè)比較大的項(xiàng)目,就沒有別人再帶著我,而是我自己一個(gè)人去完成詳細(xì)設(shè)計(jì)了。大概詳細(xì)設(shè)計(jì)寫了20天左右,我被通知當(dāng)天把手上的一份詳細(xì)設(shè)計(jì)寫 完,第二天進(jìn)入方式設(shè)計(jì)小組進(jìn)行方式的設(shè)計(jì)。

    進(jìn)入方式小組以后,接到的任務(wù)就是好幾個(gè)編寫DB操作方面的代碼自動化生成工具。由于這次DB 方面并沒有非常強(qiáng)制性的那種規(guī)約,所以SQL語句的編寫可以說比較隨意,這就給我工具的編寫帶來了很大的難度和挑戰(zhàn)。這次負(fù)責(zé)管理方式小組的人仍然是進(jìn)公 司以后經(jīng)常帶著我的那位技術(shù)專家,所以也真算很巧呢。寫工具其實(shí)很對自身代碼編寫的提高也很有好處,因?yàn)槭紫瓤蛻裟抢镔Y料會不斷修改,這些工具你為了以后 客戶更新資料后你能順利更新工具,你需要設(shè)計(jì)一個(gè)優(yōu)良的Framework,不一定需要多么復(fù)雜的Framework,不過一定要盡量把程序各方面的耦合 度盡量降低,這樣才有利于自己對工具進(jìn)行擴(kuò)展。緊接著很快,項(xiàng)目代碼編寫開始了,我的任務(wù)算中等偏上,有2個(gè)畫面和一個(gè)批處理需要編寫,復(fù)雜度還算比較繁 一點(diǎn)。這次項(xiàng)目需要編寫JUnit程序,每天都要進(jìn)行回歸測試,保證代碼Method的正確性。JUnit雖然自己會用,但是從來沒有在真正的項(xiàng)目中使 用,所以在真正用的時(shí)候感覺有點(diǎn)手足無措。以前做JUnit從來都是覺得給個(gè)參數(shù),檢測一個(gè)返回值就好了,其實(shí)不是那么回事,業(yè)務(wù)邏輯復(fù)雜了,自己需要做 大量的Stub來模擬真實(shí)的Class的返回值。設(shè)計(jì)一個(gè)好的Stub是比較困難的,特別在數(shù)據(jù)庫內(nèi)容比較豐富的時(shí)候,一張數(shù)據(jù)庫Table就有上百個(gè) 域,工作量可見一斑了。項(xiàng)目要到05年9月中旬才會結(jié)束,所以現(xiàn)在還在緊張的開發(fā)階段。我寫了JUnit的感覺就是難點(diǎn)不在如何去寫JUnit程序,而是 如何去設(shè)計(jì)測試用例。對于我們這樣不是以測試出身的程序員來說,設(shè)計(jì)測試用例是很痛苦而且很艱難的事情,估計(jì)有過相似經(jīng)驗(yàn)的人肯定會表示贊同。

        當(dāng)然我一邊在緊張的做項(xiàng)目,對于書本的學(xué)習(xí)也沒有閑著。這段時(shí)間抓緊把侯捷的Word排版藝術(shù)掃了一遍,看完覺得收獲頗豐。雖然我以前覺得我在Word上 用得挺不錯(cuò),日常的一些操作什么的我都會,不過看這本書的中間我發(fā)現(xiàn)我還是有很多地方不會的,也學(xué)到了不少東西,在以后的Word排版中會很受到好處。由 于項(xiàng)目用到了Spring知識,所以我也看了網(wǎng)絡(luò)上那個(gè)流傳廣泛的Spring開發(fā)指南的PDF看了一遍,感覺長了見識,對IOC以及DI有了進(jìn)一步的了 解,也理解了為什么需要采用IOC以及DI。不過這個(gè)也沒有深入下去仔細(xì)看,以后等項(xiàng)目稍微空閑一點(diǎn)的時(shí)候一定再把Hibernate和Spring好好 看一下,學(xué)習(xí)人家的設(shè)計(jì)理念,提高自己能力。對了,也許最重要的是我最近在看一本書,就是《J2EE核心模式》的第二版,我當(dāng)時(shí)原來準(zhǔn)備看電子版的這本 《Core J2EE Patterns》的,不過突然在書店發(fā)現(xiàn)這本書的中文版出來了,而且譯者有熊節(jié)的名字,也就是跟侯捷一起翻譯《重構(gòu)——改善既有代碼的設(shè)計(jì)》的那個(gè)譯 者,我比較相信他翻譯的水平,于是買回來看,雖然項(xiàng)目非常緊張,我一個(gè)月算上周末需要加班在100個(gè)小時(shí)左右的樣子,但是我相信時(shí)間是海綿里的水,只要去 擠,肯定會有的。所以我到現(xiàn)在大概看了2周的樣子,已經(jīng)看了300多頁,而且感覺自己的設(shè)計(jì)視野也開闊了許多,這本書的確很好,把J2EE中常用的一些模 塊原理都說了出來,說明了為什么這么做好,這么做如何減少了耦合性,提高了可維護(hù)性等等,總之,有1年以上J2EE開發(fā)經(jīng)驗(yàn)而且覺得自己對J2EE有了比 較好的了解的開發(fā)人員我強(qiáng)烈推薦看這本書。看了這本書以后我都在回想以前設(shè)計(jì)的一些框架,一些模塊,覺得自己有很多地方當(dāng)時(shí)設(shè)計(jì)的時(shí)候覺得很精巧,不過卻 屬于弄巧成拙,加大了模塊的耦合性,所以在修改的時(shí)候比較難于下手。

    posted @ 2005-12-26 21:43 Dion 閱讀(2592) | 評論 (8)編輯 收藏

    主站蜘蛛池模板: 最近2019年免费中文字幕高清| 人禽伦免费交视频播放| 亚洲午夜成人精品无码色欲| 亚洲色www永久网站| 国产亚洲人成在线影院| 国产精品免费观看视频| 一区二区三区四区免费视频| 亚洲成人免费电影| 成在线人永久免费视频播放| 亚洲色欲久久久久综合网| 亚洲图片在线观看| 亚洲午夜成人精品无码色欲| 一本久久A久久免费精品不卡| 久久99精品免费视频| 毛片a级三毛片免费播放| 亚洲福利中文字幕在线网址| 国产亚洲综合网曝门系列| 亚洲成a人片在线观| 国产AV无码专区亚洲AV麻豆丫| 黄色网址在线免费| 亚洲国产美国国产综合一区二区 | 亚洲人成色77777| 亚洲白色白色永久观看| 国产亚洲福利精品一区二区 | 亚洲欧美国产精品专区久久| jizz免费观看视频| 免费AA片少妇人AA片直播| 亚洲国产午夜中文字幕精品黄网站| 亚洲大片在线观看| 亚洲AV无码成人精品区狼人影院| 在线观看免费无码视频| 24小时免费直播在线观看| 毛茸茸bbw亚洲人| 亚洲欧美日韩综合久久久久| 中文字幕无线码中文字幕免费| 成人奭片免费观看| 国产亚洲av片在线观看16女人 | 亚洲免费福利在线视频| 中文字幕乱理片免费完整的| 成人免费一区二区无码视频| 亚洲精品白浆高清久久久久久|