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

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

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

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

        JUnit的源碼相比于spring和hibernate來說比較簡單,但麻雀雖小,五臟俱全,其中用到了比較多的設計模式。很多人已經在網上分享了他們對JUnit源碼解讀心得,我這篇小文談不出什么新意,本來不打算寫,可最近工作上暫時無事可做,那就寫寫吧,結合《設計模式》來看看。
        我讀的是JUnit3.0的源碼,目前JUnit已經發布到4.0版本了,盡管有比較大的改進,但基本的骨架不變,讀3.0是為了抓住重點,省去對旁支末節的關注。我們來看看JUnit的核心代碼,也就是Junit.framework包,除了4個輔助類(Assert,AssertFailedError,Protectable,TestFailure),剩下的就是我們需要重點關注的了。我先展示一張UML類圖:

        我們先不去關注TestDecorator類(此處是Decorator模式,下篇文章再講),看看Test接口,以及它的兩個實現類TestCase和TestSuite。很明顯,此處用到了Command模式,為什么要使用這個模式呢?讓我們先來看看什么是Command模式。

    Command模式

    Command模式是行為型模式之一

    1.意圖:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或者記錄請求日志,以及支持可撤銷的操作。
    2.適用場景:
    1)抽象出待執行的動作以參數化對象,Command模式是回調函數的面向對象版本。回調函數,我想大家都明白,函數在某處注冊,然后在稍后的某個時候被調用。
    2)可以在不同的時刻指定、排列和執行請求。
    3)支持修改日志,當系統崩潰時,這些修改可以被重做一遍。
    4)通過Command模式,你可以通過一個公共接口調用所有的事務,并且也易于添加新的事務。


    3。UML圖:
       

    4.效果:
    1)命令模式將調用操作的對象與如何實現該操作的對象解耦。
    2)將命令當成一個頭等對象,它們可以像一般對象那樣進行操縱和擴展
    3)可以將多個命令復合成一個命令,與Composite模式結合使用
    4)增加新的命令很容易,隔離對現有類的影響
    5)可以與備忘錄模式配合,實現撤銷功能。

        在了解了Command模式之后,那我們來看JUnit的源碼,Test接口就是命令的抽象接口,而TestCase和TestSuite是具體的命令
    //抽象命令接口
    package junit.framework;

    /**
     * A <em>Test</em> can be run and collect its results.
     *
     * 
    @see TestResult
     
    */
    public interface Test {

        
    /**
         * Counts the number of test cases that will be run by this test.
         
    */
        
    public abstract int countTestCases();
        
    /**
         * Runs a test and collects its result in a TestResult instance.
         
    */
        
    public abstract void run(TestResult result);
    }

    //具體命令一

    public abstract class TestCase extends Assert implements Test {
        
    /**
         * the name of the test case
         
    */
        
    private final String fName;
        
    /**
       

    //具體命令二

    public class TestSuite implements Test {
         

    由此帶來的好處:
    1.客戶無需使用任何條件語句去判斷測試的類型,可以用統一的方式調用測試和測試套件,解除了客戶與具體測試子類的耦合
    2.如果要增加新的TestCase也很容易,實現Test接口即可,不會影響到其他類。
    3.很明顯,TestSuite是通過組合多個TestCase的復合命令,這里使用到了Composite模式(組合)
    4.盡管未實現redo和undo操作,但將來也很容易加入并實現。

        我們上面說到TestSuite組合了多個TestCase,應用到了Composite模式,那什么是Composite模式呢?具體來了解下。

    Composite模式

    composite模式是對象結構型模式之一。
    1.意圖:將對象組合成樹形結構以表示“部分——整體”的層次結構。使得用戶對單個對象和組合結構的使用具有一致性。

    2.適用場景:
    1)想表示對象的部分-整體層次
    2)希望用戶能夠統一地使用組合結構和單個對象。具體到JUnit源碼,我們是希望用戶能夠統一地方式使用TestCase和TestSuite

    3.UML圖:

          

    圖中單個對象就是樹葉(Leaf),而組合結構就是Compoiste,它維護了一個Leaf的集合。而Component是一個抽象角色,給出了共有接口和默認行為,也就是JUnit源碼中的Test接口。

    4.效果:
    1)定義了基本對象和組合對象的類層次結構,通過遞歸可以產生更復雜的組合對象
    2)簡化了客戶代碼,客戶可以使用一致的方式對待單個對象和組合結構
    3)添加新的組件變的很容易。但這個會帶來一個問題,你無法限制組件中的組件,只能靠運行時的檢查來施加必要的約束條件

        具體到JUnit源碼,單個對象就是TestCase,而復合結構就是TestSuite,Test是抽象角色只有一個run方法。TestSuite維護了一個TestCase對象的集合fTests:

         private Vector fTests= new Vector(10); 
          
    /**
         * Adds a test to the suite.
         
    */
        
    public void addTest(Test test) {
            fTests.addElement(test);
        }
        /**
         * Runs the tests and collects their result in a TestResult.
         
    */
        
    public void run(TestResult result) {
            
    for (Enumeration e= tests(); e.hasMoreElements(); ) {
                  
    if (result.shouldStop() )
                      
    break;
                Test test
    = (Test)e.nextElement();
                test.run(result);
            }
        }

    當執行run方法時遍歷這個集合,調用里面每個TestCase對象的run()方法,從而執行測試。我們使用的時候僅僅需要把TestCase添加到集合內,然后用一致的方式(run方法)調用他們進行測試。

    考慮使用Composite模式之后帶來的好處:
    1)JUnit可以統一地處理組合結構TestSuite和單個對象TestCase,避免了條件判斷,并且可以遞歸產生更復雜的測試對象
    2)很容易增加新的TestCase。


    參考資料:《設計模式——可復用面向對象軟件的基礎》
              《JUnit設計模式分析》 劉兵
              JUnit源碼和文檔









        

    posted @ 2007-04-05 15:10 dennis 閱讀(4600) | 評論 (3)編輯 收藏

        org.springframework.core.io包中主要是各樣的Resource類,Spring的 Resource 接口是為了提供更強的訪問底層資源能力的抽象。具體的用法參考spring reference。這個包的類圖非常簡單,已經有人畫的很清晰了,我直接拿過來,來自:Spring代碼賞析:Resource類層次



    相當巧妙的地方在于,為何AbstractResource的子類有的override了getFile()而有的沒有?這是因為在AbstractResource的getFile()方法設計為拋出異常,如果子類沒有重寫此方法,說明子類不支持通過絕對路徑查找資源的方式,而override的子類則提供自己的實現。這里通過類的層次設計,充分利用繼承帶來的優點,避免了大量的條件語句。

    posted @ 2007-04-05 09:23 dennis 閱讀(2690) | 評論 (0)編輯 收藏

        好久沒看新的小說了,也就追著看《異人》、《新宋》和《大宋時代周刊》,更新不快,我也沒多少時間天天看小說。今天上起點,看封推仍然是一大堆的《XXX到異界》的題材,巨無語。《魔煉》這題目也算普普通通,看了書評,評價還不錯。讀了7,8章,感覺還真不錯,煉金術師的故事,蠻有趣,不過感情的描寫上不夠合理,把握的并不好,維維安牧師同學就這么愛上了我們的男豬腳。另外,看來作者也是喜歡玩WOW的,不少術語和戰斗場面很像游戲里的。WOW已經放棄好久了,資料篇出來倒是很想再去艾澤拉斯大陸重新歷險一番,嘿嘿。

    posted @ 2007-04-03 19:35 dennis 閱讀(529) | 評論 (0)編輯 收藏

    二叉查找樹(binary search tree)

    1)概念:對于樹中的每個節點n,其左子節點中保存的所有數值都小于n保存的數值,右子節點保存的數值都大于n保存的數值。

    2)二叉查找樹可以實現更為優越的查找性能,主要實現方式有數組和鏈表結構,相比較而言,鏈表實現更為容易,因為數組實現刪除和添加功能需要移動數組元素(如填補刪除空位等)


    今天下午在打印問題搞定后用C#實現了一下,比java版本比較有趣的使用C#的delegate來代替遍歷二叉樹時的visit方法,這樣一來可以在遍歷時對節點進行你所想要的任何操作。我們知道C#的delegate是類型化的函數指針,而C++的函數指針可以模仿動態語言的閉包或者匿名函數。這里也有這樣的味道。

    代碼如下,只實現了整數型的,節點定義:
      public  class BSTIntNode
        {
            
    public int value;
            
    public BSTIntNode left;
            
    public BSTIntNode right;

            
    public BSTIntNode(int value, BSTIntNode left, BSTIntNode right)
            {
                
    this.value = value;
                
    this.left = left;
                
    this.right = right;
            }

            
    public BSTIntNode(int value)
            {
                
    this.value = value;
                
    this.left = null;
                
    this.right = null;
            }
        }

    然后定義一個Delegate,作為遍歷時的訪問方法:

     public delegate void Visit(BSTIntNode node);

    然后就是二叉樹的實現,刪除算法只實現了復制刪除法:

    public class BSTIntTree
        {
            
    protected BSTIntNode root;
          
            
    public Visit visit;

            
    public BSTIntTree()
            {
                
    this.root = null;
            }

            
    private BSTIntNode Search(BSTIntNode node, int el)
            {
                
    while (node != null)
                {
                    
    if (el == node.value)
                        
    return node;
                    
    else if (el < node.value)
                        node 
    = node.left;
                    
    else
                        node 
    = node.right;
                }
                
    return null;
            }

            
    //查找
            public BSTIntNode Search(int el)
            {
                
    return Search(root, el);
            }

            
    //廣度優先遍歷,利用隊列實現,至上而下,至左而右
            public void BreadthFirst()
            {
                BSTIntNode p 
    = root;
                Queue queue 
    = new ListQueue();
                
    if (p != null)
                {
                    queue.Enqueue(p);
                    
    while (!queue.IsEmpty())
                    {
                        p 
    = (BSTIntNode)queue.Dequeue();
                        visit(p);
                        
    if (p.left != null)
                            queue.Enqueue(p.left);
                        
    if (p.right != null)
                            queue.Enqueue(p.right);
                    }
                }
            }

            
    //深度優先遍歷,遞歸實現線序,中序和后序

            
    //先序
            protected void PreOrder(BSTIntNode p)
            {
                
    if (p != null)
                {
                    visit(p);
                    PreOrder(p.left);
                    PreOrder(p.right);
                }
            }

            
    public void PreOrder()
            {
                PreOrder(root);
            }
            
    //中序
            protected void InOrder(BSTIntNode p)
            {
                
    if (p != null)
                {
                    InOrder(p.left);
                    visit(p);
                    InOrder(p.right);
                }
            }

            
    public void InOrder()
            {
                InOrder(root);
            }

            
    //后序
            protected void PostOrder(BSTIntNode p)
            {
                
    if (p != null)
                {
                    PostOrder(p.left);
                    PostOrder(p.right);
                    visit(p);
                }
            }

            
    public void PostOrder()
            {
                PostOrder(root);
            }

            
    //插入節點操作
            public void Insert(int el)
            {
                BSTIntNode p 
    = root, prev = null;

                
    //查找節點位置
                while (p != null)
                {
                    prev 
    = p;
                    
    if (p.value < el)
                        p 
    = p.right;
                    
    else
                        p 
    = p.left;
                }

                
    if (root == null)  //空樹
                    root = new BSTIntNode(el);
                
    else if (prev.value < el)   //大于節點,插入右子樹
                    prev.right = new BSTIntNode(el);
                
    else
                    prev.left 
    = new BSTIntNode(el);
            }

            
    //復制刪除法的實現,歸并刪除法可能改變樹的高度
            public void Delete(int el)
            {
                BSTIntNode node, p 
    = root, prev = null;

                
    //查找節點位置
                while (p != null&&p.value!=el)
                {
                    prev 
    = p;
                    
    if (p.value < el)
                        p 
    = p.right;
                    
    else
                        p 
    = p.left;
                }
                node 
    = p;
                
    if (p != null && p.value == el)
                {
                    
    if (node.right == null)
                        node 
    = node.left;
                    
    else if (node.left == null)
                        node 
    = node.right;
                    
    else
                    {
                        BSTIntNode temp 
    = node.left;
                        BSTIntNode previous 
    = node;
                        
    while (temp.right != null)  //查找左字節數的最右子節點
                        {
                            previous 
    = temp;
                            temp 
    = temp.right;
                        }
                        node.value 
    = temp.value;
                        
    if (previous == node)
                            previous.left 
    = temp.left;
                        
    else
                            previous.right 
    = temp.left;
                    }
                    
    if (p == root)
                        root 
    = node;
                    
    else if (prev.left == p)
                        prev.left 
    = node;
                    
    else
                        prev.right 
    = node;
                }
                
    else if (root != null)
                {
                    Console.WriteLine(
    "沒有找到節點:{0}", el);
                }
                
    else
                    Console.WriteLine(
    "樹為空!");
            }

        }

    注意,在樹中我們維持了一個Visit的delegate,看看使用方法:

     public static void Main(string[] args)
            {
               BSTIntTree tree
    =new BSTIntTree();
               
    int []num={10,20,6,12,23,15,8};
               
    for (int i = 0; i < num.Length; i++)
                   tree.Insert(num[i]);
               
    //添加遍歷處理函數,可以有多個 
               tree.visit += new Visit(printNode);
              
               Console.WriteLine(
    "廣度優先遍歷");
               tree.BreadthFirst();
               Console.WriteLine(
    "先序");
               tree.PreOrder();
               Console.WriteLine(
    "中序");
               tree.InOrder();
               Console.WriteLine(
    "后序");
               tree.PostOrder();

               tree.Delete(
    8);
               tree.Delete(
    15);
               Console.WriteLine(
    "刪除后廣度優先遍歷");
               tree.BreadthFirst();

            }
            
    public static void printNode(BSTIntNode node)
            {
                Console.WriteLine(
    "訪問節點:{0}", node.value);
            }

    可以看到,C#的delegate機制非常有趣,如果在java中恐怕需要用inner class來實現了。


    posted @ 2007-04-02 17:29 dennis 閱讀(1623) | 評論 (1)編輯 收藏

        這個星期我的任務就是處理一些報表的打印問題,因為我算項目組里對jasperreport比較熟悉的了,這個東東也是我引進到這個項目。ireport畫報表,使用struts的action輸出PDF到瀏覽器,這是我們目前的解決方案。今天遇到一個ireport解決不了的要求——合并單元格。類似下面這樣的表結構:
    ----------------------------------------------
              |          |__c_____________
       dept   | value    |__b_____________
              |          |  a
    --------------------------------------------------------
    也就是需要跨行,跨列!-_-。在html表格中解決這個很簡單,只要設置單元格的colspan和rowspan即可。我在ireport沒有找到解決方案,如果您知道,請不吝賜教。查找資料弄了兩個小時沒進展,決定自己用iText寫吧,通過google、baidu資料順利達到了我的要求,僅在此記錄下遇到的問題和解決方法。

    一。一個HelloWorld實例:
    package com.lowagie.examples.general;

      
    import java.io.FileOutputStream;
      
    import java.io.IOException;

      
    import com.lowagie.text.*;
      
    import com.lowagie.text.pdf.PdfWriter;

      
    /**
       * Generates a simple 'Hello World' PDF file.
       *
       * 
    @author blowagie
       
    */

      
    public class HelloWorld {

        
    /**
         * Generates a PDF file with the text 'Hello World'
         *
         * 
    @param args no arguments needed here
         
    */
        
    public static void main(String[] args) {

          System.out.println(
    "Hello World");

          
    // step a: creation of a document-object
          Document document = new Document();
          
    try {
            
    // step b:
            
    // we create a writer that listens to the document
            
    // and directs a PDF-stream to a file
            PdfWriter.getInstance(document,new FileOutputStream("HelloWorld.pdf"));

            
    // step c: we open the document
            document.open();
            
    // step d: we add a paragraph to the document
            document.add(new Paragraph("Hello World"));
          } 
    catch (DocumentException de) {
            System.err.println(de.getMessage());
          } 
    catch (IOException ioe) {
            System.err.println(ioe.getMessage());
          }

          
    // step e: we close the document
            document.close();
          }
        }
    可以看到一個PDF文件的輸出,總共只需要5個步驟
    a.創建一個Document實例
      Document document = new Document();
    b.將Document實例和文件輸出流用PdfWriter類綁定在一起
      PdfWriter.getInstance(document,new FileOutputStream("HelloWorld.pdf"));
    c.打開文檔
      document.open();
    d.在文檔中添加文字
      document.add(new Paragraph("Hello World"));
    e.關閉文檔
      document.close();
    這樣5個步驟,就可以生成一個PDF文檔了。

    二。如何使用jsp、servlet輸出iText生成的pdf?
      如果每次都在服務端生成一個PDF文件給用戶,不僅麻煩,而且浪費服務器資源,最好的方法就是以二進制流的形式輸送到客戶端。
    1)JSP輸出:
    <%@ page import="java.io.*,java.awt.Color,com.lowagie.text.*,com.lowagie.text.pdf.*"%>

    <%
    response.setContentType
    "application/pdf" );
    Document document 
    = new Document();
    ByteArrayOutputStream buffer
    = new ByteArrayOutputStream();
    PdfWriter writer
    =
    PdfWriter.getInstance( document, buffer );
    document.open();
    document.add(
    new Paragraph("Hello World"));
    document.close();
    DataOutput output 
    =
    new DataOutputStream
    ( response.getOutputStream() );
    byte[] bytes = buffer.toByteArray();
    response.setContentLength(bytes.length);
    forint i = 0;
    < bytes.length;
    i
    ++ )
    {
    output.writeByte( bytes[i] );
    }
    %>

    2)servlet輸出,稍微改造下就可以使用在struts中:
    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import com.lowagie.text.*;
    import com.lowagie.text.pdf.*;
    public void doGet
    (HttpServletRequest request,
    HttpServletResponse response)
    throws IOException,ServletException
    {
    Document document 
    =
    new Document(PageSize.A4, 36,36,36,36);
    ByteArrayOutputStream ba
    = new ByteArrayOutputStream();
    try
    {
    PdfWriter writer 
    =
    PdfWriter.getInstance(document, ba);
    document.open();
    document.add(
    new
    Paragraph(
    "Hello World"));
    }
    catch(DocumentException de)
    {
    de.printStackTrace();
    System.err.println
    (
    "A Document error:" +de.getMessage());
    }
    document.close();
    response.setContentType
    (
    "application/pdf");
    response.setContentLength(ba.size());
    ServletOutputStream out
    = response.getOutputStream();
    ba.writeTo(out);
    out.flush();
    }


    三。如何輸出中文?
        首先需要下載iTextAsian.jar包,可以到iText的主站上下,ireport也是需要這個包的。然后定義中文字體:
        private static final Font getChineseFont() {
            Font FontChinese 
    = null;
            
    try {
                BaseFont bfChinese 
    = BaseFont.createFont("STSong-Light",
                        
    "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                FontChinese 
    = new Font(bfChinese, 12, Font.NORMAL);
            } 
    catch (DocumentException de) {
                System.err.println(de.getMessage());
            } 
    catch (IOException ioe) {
                System.err.println(ioe.getMessage());
            }
            
    return FontChinese;
        }

    我將產生中文字體封裝在方法內,自定義一個段落PDFParagraph繼承自Paragraph,默認使用中文字體:
    class PDFParagraph extends Paragraph {
            
    public PDFParagraph(String content) {
                
    super(content, getChineseFont());
            }
        }

    使用的時候就可以簡化了:

    Paragraph par = new PDFParagraph("你好");

    四。如何設置PDF橫向顯示和打???

    Rectangle rectPageSize = new Rectangle(PageSize.A4);// 定義A4頁面大小
    rectPageSize = rectPageSize.rotate();// 加上這句可以實現A4頁面的橫置
    Document doc = new Document(rectPageSize,50,50,50,50);//4個參數,設置了頁面的4個邊距

    五。如何設置跨行和跨列?

    使用PdfPTable和PdfPCell 是沒辦法實現跨行的,只能跨列,要跨行使用com.lowagie.text.Table和com.lowagie.text.Cell類,Cell類有兩個方法:setRowspan()和setColspan()。

    六。如何設置單元格邊界寬度?

    Cell類的系列setBorderWidthXXXX()方法,比如setBorderWidthTop(),setBorderWidthRight()等

    七。如何設置表頭?
    希望每一頁都有表頭,可以通過設置表頭來實現。對于PdfPTable類來說,可以這樣設置:
    PdfPTable table = new PdfPTable(3);
    table.setHeaderRows(
    2); // 設置了頭兩行為表格頭

    而對于om.lowagie.text.Table類,需要在添加完所有表頭的單元格后加上一句代碼:
    table.endHeaders();

    八。如何設置列寬?

    Table table = new Table(8);
    float[] widths = { 0.10f0.15f0.21f0.22f0.08f0.08f0.10f,
                        
    0.06f };
    table.setWidths(widths);

    上面的代碼設置了一個有8列的表格,通過一個float數組設置列寬,這里是百分比。

    九。單元格內段落文字居中和換行?
    居中通過Cell類來設置,一開始我以為設置段落對齊就可以了,沒想到是需要設置單元格:

    cell.setHorizontalAlignment(Element.ALIGN_CENTER);


    轉義符\n實現。在我的這個應用中,因為數據庫取出的數據是為了顯示在html上的,所以有很多<br>標簽,可以使用正則表達式替換成"\n"
    "<br>1.測試<br>2.測試2".replaceAll("<br>|</br>","\n");

    十。如何顯示頁碼?
    復雜的頁碼顯示和水印添加,需要使用到PdfPageEventHelper、PdfTemplate等輔助類,具體的例子參見iText的文檔,如果只是為了簡單的顯示頁數,可以使用下面的代碼:
                HeaderFooter footer = new HeaderFooter(new Phrase("頁碼:",getChineseFont()), true);
                footer.setBorder(Rectangle.NO_BORDER);
                document.setFooter(footer);
                document.open();
    你可能注意到了,添加footer需要在document.open之前。

    posted @ 2007-04-02 15:52 dennis 閱讀(12820) | 評論 (9)編輯 收藏

    我們一直強調單元測試的重要性,但是有一個問題可能沒有認真去想過,測試是重要的,但是我們測試什么呢?最近重讀《單元測試之道》,書中給出了答案:Right-BICEP

    1.Right——正確

    很顯然,如果代碼運行的結果與你預期的不符合,那么這段代碼肯定是有問題的。需要注意的是,Right并意味著正確,因為正確只是相對你所期望的結果而言,而對于用戶需求也許就是錯誤的。

    2.B——邊界條件
    尋找邊界條件是單元測試最有價值的工作之一,因為bug一般出現在邊界條件上,你常常需要考慮下面這些邊界條件:
    1)完全偽造或者不一直的數據進行輸入
    2)格式錯誤的數據,比如錯誤的URL,Email地址
    3)空值或者不完整值,比如0,null
    4)與常理相去甚遠的數據,比如人有10000歲?
    5)如果要求傳入的是一個不允許重復數據的list,你傳入一個有重復數據的看看出現什么情況
    6)如果需要傳入的有序的集合,你傳入一個無序的看看結果
    7)不按照次序地執行,比如未登錄就嘗試操作某功能等
    對于邊界條件,可以按照CORRECT的順序去嘗試:
    Conformance——一致性,值是否和預期的一樣
    Ordering——順序性,值是否如預期的那樣,有序或者無序
    Range——區間性,值是否處于合理的范圍內
    Reference——引用,值是否引用了代碼無法空值的外部資源
    Existence——值是否存在,為空?為0?不在集合內?
    Cardinatity——基數性,檢查你的函數能否正確地計數,不多不少
    Time——所有的事件的發生是否按照預期的順序,性能上滿足要求?

    3.Inverse——檢查反向引用
    如果方法導致某個結果,嘗試以另一個方法能否返回最初的狀態?與原狀態是否符合預期?

    4。Cross——交叉檢查
    通過不同的方法檢查一個方法產生的結果是否正確,比如用Math.sqrt方法檢查自己編寫的求平方根的方法是否正確。另外的方式,以一種數量去檢查另一種數量,比如圖書館借出的書加上架上的書的總數是固定,可以用借出的書來檢查架上的書的數量是否正確。

    5.E——強制錯誤條件的產生

    一般我們所能想到的環境因素:
    1)內存耗光
    2)磁盤用滿
    3)時鐘出問題
    4)網絡不可用或者有問題
    5)系統過載
    6)調色板顏色數目有限
    7)顯示分辨率過高

    再比如JDK版本差異,我就為這個問題頭痛過:)

    6.Performance——性能
    每天或者每隔幾天運行一下一個粗糙簡單的性能測試,能夠保證你不會在給用戶演示的時候出現尷尬的場面。

    盡管書上是講了這么多測試這個、測試那個,我想真實的項目場景中應該根據需要采取特定的測試策略,比如你總不能對于一個單機應用需要考慮地震震斷海底光纜引發的問題。就我自己而言,因為項目組中似乎只有我對JUnit等單元測試工具充滿興趣,有經驗的老程序員是自己寫一個帶Main方法的Test類進行測試,而更多的人根本就不知道單元測試或者知道也不感興趣,在沒有壓力的情況下,要求自己考慮這么多的測試內容,難矣。今天試用了下NUnit,感覺比JUnit難用多了,JUnit與Eclipse的結合非常簡便。






    posted @ 2007-03-31 19:18 dennis 閱讀(388) | 評論 (0)編輯 收藏

    上國外一站點下載一本PDF文檔,沒想到:

    We're sorry, but access is denied to that document.

    This might be because you are accessing this site from a machine in China. Because of a massive amount of robot traffic from Chinese machines, we've had to take the unfortunate step of blocking access from those IPs.

    If you feel that access has been denied in error, please contact our support folks.


    無言以對。



    posted @ 2007-03-30 14:57 dennis 閱讀(364) | 評論 (3)編輯 收藏

    有了前一篇C#鏈表的實現,實現棧和隊列易如反掌。

    棧,利用單向鏈表實現:
    public?abstract?class?AbstractStack
    ????{
    ????????
    public?abstract?Object?Pop();
    ????????
    public?abstract?void?Push(Object?obj);
    ????????
    public?abstract?bool?IsEmpty();
    ????????
    public?abstract?Object?Top();
    ????????
    public?abstract?void?Clear();
    ????}

    ????
    public?class?Stack?:?AbstractStack
    ????{
    ????????
    private?SList?list;
    ????????
    public?Stack()
    ????????{
    ????????????list?
    =?new?SList();
    ????????}
    ????????
    public?override?bool?IsEmpty()
    ????????{
    ????????????
    return?list.IsEmpty();
    ????????}
    ????????
    public?override?void?Push(Object?obj)
    ????????{
    ????????????list.Push(obj);
    ????????}
    ????????
    public?override?object?Pop()
    ????????{
    ????????????
    return?list.Pop();
    ????????}
    ????????
    public?override?object?Top()
    ????????{
    ????????????
    return?list.getTail();
    ????????}
    ????????
    public?override?void?Clear()
    ????????{
    ????????????list.Clear();?
    ????????}
    ????}

    隊列的實現,通過雙向鏈表實現,對于環形數組的實現請參考《數組結構之棧與鏈表》:
    ?public?interface?Queue
    ????{
    ????????
    bool?IsEmpty();
    ????????
    void?Enqueue(Object?obj);
    ????????Object?Dequeue();
    ????????Object?First();
    ????}

    ????
    public?class?ListQueue:Queue
    ????{
    ????????
    private?LinkedList?list;
    ????????
    public?ListQueue()
    ????????{
    ????????????list?
    =?new?LinkedList();
    ????????}

    ????????
    public?bool?IsEmpty()
    ????????{
    ????????????
    return?list.IsEmpty();
    ????????}

    ????????
    public?void?Enqueue(Object?obj)
    ????????{
    ????????????list.Push(obj);
    ????????}
    ????????
    public?Object?Dequeue()
    ????????{
    ????????????
    return?list.Shift();
    ????????}

    ????????
    public?Object?First()
    ????????{
    ????????????
    return?list.getHead();
    ????????}
    ????}

    posted @ 2007-03-30 09:44 dennis 閱讀(2198) | 評論 (1)編輯 收藏

         摘要: C#實現單向和雙向鏈表。  閱讀全文

    posted @ 2007-03-29 17:02 dennis 閱讀(1998) | 評論 (1)編輯 收藏

    我不知道我是不是頭腦發熱,突然對編譯原理,特別是ANTLR的使用很感興趣,轉個別人總結的步驟。

    1.先利用ANTLR之類的編譯器生成工具,做一個小程序(如上面提到的HTML文件轉化成純文本文件的程序),所需知識只是正則表達式的基本知識和生成工具本身的使用方法 這樣做的好處是:

    1)可以體會到編譯原理的實用性,提高學習興趣

    2)入門容易,消除編譯原理學習的畏難情緒.

    3)獲得詞法分析器和語法分析器的感性認識,有利于加深對理論的理解.

    4)獲得編譯器自動生成工具(compiler compiler)的使用經驗,提高解決實際問題的能力.(實際工作很多都不是手編而是利用工具的)

    2.象ANTLR之類的工具是開源(open source)的,可研究其源碼,以便必要時自己手編分析程序.

    3.回過頭來看編譯原理教材. 這時大概會發現,很多理論很容易懂,剩下的只有上面說的幾個難點,多看幾遍,重點突破.

    4.結合教材所附源碼,進一步加深對教材的理解

    我決定充實下這篇文章,今天讀了anstlr很多文章,來自莊表偉的anstlr系列學習筆記。感覺編譯原理并非我想象中那么困難,實現一個簡單的腳本解釋引擎對我來說還是完全可以做到的,發現我前段時間花大力氣學習正則表達式派上了用場,理解起來事半功倍。我決定買本《編譯原理》方面的書籍老老實實讀一下。不知道有沒有人給我推薦一本?



    posted @ 2007-03-29 13:42 dennis 閱讀(703) | 評論 (0)編輯 收藏

    僅列出標題
    共56頁: First 上一頁 43 44 45 46 47 48 49 50 51 下一頁 Last 
    主站蜘蛛池模板: 永久黄色免费网站| 一级大黄美女免费播放| 亚洲熟妇无码久久精品| 亚洲成年轻人电影网站www| 亚洲一区二区三区香蕉| 亚洲毛片αv无线播放一区| 亚洲日韩乱码中文无码蜜桃臀网站 | 处破女第一次亚洲18分钟| 亚洲另类无码一区二区三区| 亚洲熟妇成人精品一区| 亚洲日韩国产AV无码无码精品| 亚洲熟妇AV日韩熟妇在线| 亚洲中文字幕无码mv| 亚洲国产aⅴ成人精品无吗| 美女裸体无遮挡免费视频网站| 免费国产黄网站在线观看动图| 一区二区三区免费在线观看| 一级有奶水毛片免费看| 大地资源在线资源免费观看| 亚洲视频免费在线观看| 国产精品免费精品自在线观看| 国产一卡2卡3卡4卡无卡免费视频| 免费电视剧在线观看| 四虎在线播放免费永久视频| 亚洲人成网站色在线入口| 亚洲国产一二三精品无码| 在线电影你懂的亚洲| 亚洲一区免费视频| 在线观看亚洲视频| 四虎国产精品免费永久在线| 最近中文字幕高清免费中文字幕mv | 亚洲欧洲日韩极速播放| 真人无码作爱免费视频| 中文成人久久久久影院免费观看| 色猫咪免费人成网站在线观看| 99久久免费国产精品特黄| 日韩免费一区二区三区| 亚洲中文字幕在线第六区| 亚洲精品网站在线观看你懂的| 亚洲色大18成人网站WWW在线播放| 美女视频黄频a免费大全视频|