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

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

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

    Vincent.Chan‘s Blog

    常用鏈接

    統計

    積分與排名

    網站

    最新評論

    [TDD開發的全過程] 二、開發PhoneManager等類

    一、前言

    今天我把文章的名稱改了一下,想把它寫成關于TDD實踐的一系列文章。前一篇是設計,這一篇開始是開發。

    TDD 我是聞名已久,在過去實際開發中也經常用junit來寫單元測試,但真正的TDD卻從來沒有嘗試過。不過單元測試寫得久了,發現TDD確實有它誘人的地 方,也許它真的可以帶我領略一個新的編程世界。于是,又再次翻開BOB的那本〈敏捷**開發〉(去年只看了一半),現在就學用結合吧。

    在BOB 那本書中,初始那個保齡球的TDD實踐例子,不錯!很詳細。不過,我覺著寫得過于冗長了,我在昨晚是一目十行看完的。BOB無非想通過這個例子告訴我們幾 件關于TDD的重要觀念:(1)先寫測試,再讓測試通過。(2)從測試來考慮問題,也就是TDD的本意--面向測試編程。(3)測試應該自頂向下(4)測 試為重構提供了正確性的驗證,測試和重構是TDD中兩條不可缺少的腿。

    我認為TDD至少有如下好處:
    (1)看問題的角度發生了變化,從測試角度看問題,讓你的程序靈活性更高。一個類,測試代碼是一個使用者,程序中的其他類是第二個使用者,所以這個類,就必須要靈活到適應兩個使用者。而靈活帶來的是解偶和可擴展的好處。
    (2)即刻得到了單元測試代碼。單元測試代碼對于軟件來說,就象安全帽對于建筑工人的重要性一樣。而且單元測試代碼就是最好的文檔。

    不過我的一些不同的觀點:TDD不應該拋開最初的概要設計
    我 周未喜歡去戶外玩,在戶外可變性很大,但我喜歡有一個計劃,而在實際戶外時再根據情況靈活應變改變計劃。我認為TDD也類似,TDD是一種很講究實際的編 程方法,但初始的概要設計還是要有的,它至少讓我們對開發有了一個大致的路線圖。然后,我們再在TDD中根據實際情況再調整,但設計的路線圖讓我們不至于 迷路。

    上面一堆啰嗦話講完了,讓我們開始開發吧。


    二、開發PhoneManager類

    1、先寫PhoneManager的測試類。

    在這里我面臨一個選擇,是先寫界面呢?還是先寫底層API?我想,先寫界面很難寫測試代碼,而且界面在設計時已經定下來了,基本不會變了。所以權衡了一下,還是先寫底層API吧,根據設計圖上的界面和各種UML圖,API寫起來有法可依。

    于是我按照BOB大叔“自頂而下”的教導,先選擇了PhoneManager這個管理著Phone和PhoneGroup的類。

    另 注:“自頂而下”的教導是完全正確的,因為TDD中編程結構不確定很大。如果為了便于寫測試代碼而選擇“從下向上”,你會發現寫到“上”的時候,忽然需要 調整結構,“下”面就要做大調整,這時白費工就做大發了。就象梳頭一樣,從下往上梳你會死很慘。再用一句俗語來比喻:“毛主席得個感冒,全國人民都得痛哭 三天”^_^

    從功能上說addPhone應該是比較早用到的方法,所以先對它寫測試代碼。如下圖:

    SNAG-0000.jpg

    說明:
    (1)TDD就是這樣:正式的類還沒寫,測試的代碼就寫好了,我們下一步做的就是要使它個測試正確通過
    (2)很明顯PhoneManager在系統應該只有一個實例,所以它應該用單例模式。
    (3)一個Phone應該對應一個手機號碼,所以在構造函數里就把手機號傳入了。


    2、讓測試通過。

    界面里一大堆的錯誤,我們一一把它修正了。還好Eclipse的操作很方法,一點紅叉就能給你創建缺少的類、方法什么。在這里我體驗到先寫測試的一個好處,用Eclipse的快速修正要比一步步的創建類少打很鍵盤^_^。

    在創建正式類的過程中,我發現了上圖程序以及設計中的幾個錯誤:
    (1)13818886666超過int范圍,所以應該定義它為long型
    (2)第32句錯了。應該是 assertEquals(1, mgr.getPhones().size());

    OK,我創建好類,并且快速編寫了正式的代碼,然后運行TestPhoneManager,通過! 時間不超過十分鐘,我感覺比先寫代碼后寫測試要更快一些。不過這里的程序還是比較簡單,也許這些不能做為TDD優秀的完全證據,以后再慢慢的深入體會吧。

    下面給出所有代碼:
    import?junit.framework.TestCase;

    /**
    ?*?
    @author?chengang?2006-4-13
    ?
    */
    public?class?TestPhoneManager?extends?TestCase?{
    ????
    private?PhoneManager?mgr;

    ????
    public?static?void?main(String[]?args)?{
    ????????junit.textui.TestRunner.run(TestPhoneManager.
    class);
    ????}

    ????@Override
    ????
    protected?void?setUp()?throws?Exception?{
    ????????
    super.setUp();
    ????????mgr?
    =?PhoneManager.getInstance();
    ????}

    ????
    public?void?testAddPhone()?{
    ????????Phone?phone?
    =?new?Phone(13888816666L);
    ????????mgr.addPhone(phone);
    ????????assertEquals(
    1,?mgr.getPhones().size());
    ????????assertEquals(phone,?mgr.getPhone(
    13888816666L));
    ????}
    }


    import?java.util.Collections;
    import?java.util.HashSet;
    import?java.util.Set;

    /**
    ?*?
    @author?chengang?2006-4-13
    ?
    */
    public?class?PhoneManager?{

    ????
    private?static?PhoneManager?instance?=?new?PhoneManager();
    ????
    private?Set<Phone>?phones?=?new?HashSet<Phone>();

    ????
    private?PhoneManager()?{}

    ????
    public?static?PhoneManager?getInstance()?{
    ????????
    return?instance;
    ????}

    ????
    public?void?addPhone(Phone?phone)?{
    ????????phones.add(phone);
    ????}

    ????
    public?Set<Phone>?getPhones()?{
    ????????
    return?Collections.unmodifiableSet(phones);
    ????}

    ????
    public?Phone?getPhone(long?number)?{
    ????????
    for?(Phone?phone?:?phones)?{
    ????????????
    if?(phone.getNumber()?==?number)?{
    ????????????????
    return?phone;
    ????????????}
    ????????}
    ????????
    return?null;
    ????}

    }

    /**
    ?*?
    @author?chengang?2006-4-13
    ?
    */
    public?class?Phone?{

    ????
    private?long?number;

    ????
    public?Phone(long?number)?{
    ????????
    this.number?=?number;
    ????}

    ????
    public?long?getNumber()?{
    ????????
    return?number;
    ????}

    }


    3、測試addPhone的特殊情況

    (1)加入null,應該加不進去。
    ????public?void?testAddNullPhone()?{
    ????????mgr.addPhone(
    null);
    ????????assertEquals(
    0,?mgr.getPhones().size());
    ????}

    運行測試發現失敗。mgr.getPhone().size()返回的是2,這是受到了上一個測試加入的new Phone(13888816666L)的影響,因為mgr是單例,所以setUp雖然在每個方法前都會運行一次,但得到的實例的都是同一樣。

    有人可能覺得那就改一下測試代碼assertEquals(2,mrg.getPohnes().size())好了,這樣不就通過了嗎。但我們要謹記寫單元測試的兩個原則:獨立性和細粒度。testAddNullPhone絕對不要受到testAddPhone里數據的影響。我覺得最好的解決辦法是,給PhoneManager加一個clear方法,已清空其內的Phone對象,測試代碼唯持不變,在tearDown方法中執行mgr.clear();。

    對了mgr.getPhone().size()返回的是2,一個是testAddPhone加入的,另一個是則是因為Set允許加入null值,所以我們得在mgr.addPhone方法里加入一個null判斷。

    import?junit.framework.TestCase;

    /**
    ?*?
    @author?chengang?2006-4-13
    ?
    */
    public?class?TestPhoneManager?extends?TestCase?{
    ????
    private?PhoneManager?mgr;

    ????
    public?static?void?main(String[]?args)?{
    ????????junit.textui.TestRunner.run(TestPhoneManager.
    class);
    ????}

    ????@Override
    ????
    protected?void?setUp()?throws?Exception?{
    ????????
    super.setUp();
    ????????mgr?
    =?PhoneManager.getInstance();
    ????}

    ????@Override
    ????
    protected?void?tearDown()?throws?Exception?{
    ????????
    super
    .tearDown();
    ????????mgr.clear();
    ????}


    ????
    public?void?testAddPhone()?{
    ????????Phone?phone?
    =?new?Phone(13888816666L);
    ????????mgr.addPhone(phone);
    ????????assertEquals(
    1,?mgr.getPhones().size());
    ????????assertEquals(phone,?mgr.getPhone(
    13888816666L));
    ????}

    ????
    public?void?testAddNullPhone()?{
    ????????mgr.addPhone(
    null
    );
    ????????assertEquals(
    0
    ,?mgr.getPhones().size());
    ????}

    }


    另外,在PhoneManager中加入
    public?class?PhoneManager?{

    ????
    private?static?PhoneManager?instance?=?new?PhoneManager();
    ????
    private?Set<Phone>?phones?=?new?HashSet<Phone>();

    ????
    private?PhoneManager()?{}

    ????
    public?static?PhoneManager?getInstance()?{
    ????????
    return?instance;
    ????}

    ????
    public?void?addPhone(Phone?phone)?{
    ????????
    if?(phone?==?null)
    ????????????
    return
    ;
    ????????phones.add(phone);
    ????}

    ????
    public?Set<Phone>?getPhones()?{
    ????????
    return?Collections.unmodifiableSet(phones);
    ????}

    ????
    public?Phone?getPhone(long?number)?{
    ????????
    for?(Phone?phone?:?phones)?{
    ????????????
    if?(phone.getNumber()?==?number)?{
    ????????????????
    return?phone;
    ????????????}
    ????????}
    ????????
    return?null;
    ????}

    ????
    public?void?clear()?{
    ????????phones.clear();
    ????}


    }

    運行測試,"生命的綠色"出現^_^,通過!

    寫這些測試代碼很快,修正也相當快,不過寫文章太慢了。我的TDD的基本過程就是這樣子的了,等我把代碼寫完了再一起帖出來吧,wait............

    OK, 兩個多小時后,完成了三個類和相應的測試代碼。其中在PhoneGroup和Phone之間互設時,為了防止死循環,做了相對較較復雜的判斷。不過在寫這 里的時候,我發現以前的ITreeNode類的抽象類AbstractTreeNode中關于互設的部分可能有錯誤,所以我在這里沒有讓 PhoneGroup和Phone再去實現ITreeNode接口,必竟這里的樹結點也就兩層,相對簡單一些。

    然后我又把每個測試類的 main方法刪除了,因為Eclipse有自己的runner,JUnit自帶的text runner用不上。也把setUp.super()刪除了,這是一個空實現,要和不要都一樣,不如刪除更干凈。為了方便,我的測試代碼是放在同一目錄 (src/java)下的,我還要把它移動不同目錄(scr/test)的同一包下。另外,概要設計圖不用忙著更新,留到最后吧。就象一張地圖有些地方標 錯了,沒必要馬上重新弄出一張新的,等旅程全部結束后,再把全面更正后的地圖給后繼者用就行了。

    最后總結:這是我第一次TDD,感覺確實 很爽。我自己的體會,“先寫測試再實現的”和“先實現再寫測試”相比有這樣幾個好處:(1)編程速度更快(2)思路更清晰(3)每向前走一步都很有安全感 (因為測試代碼在后面支持著我)(4)測試代碼更全面(以前已經先實現了后,經常不想寫測試代碼,偷點懶用調試或輸出點Log,人工判斷一下就了事)。

    好了,給出全部代碼如下,僅供參考。先列出測試代碼,從測試代碼可以看到了解API實現的功能,最后再給出各類的實現代碼。


    import?junit.framework.Test;
    import?junit.framework.TestSuite;

    public?class?AllTests?{

    ????
    public?static?Test?suite()?{
    ????????TestSuite?suite?
    =?new?TestSuite("Test?for?com.wxxr.management.admin.console.smstest");
    ????????
    //$JUnit-BEGIN$
    ????????suite.addTestSuite(TestPhoneManager.class);
    ????????suite.addTestSuite(TestPhone.
    class);
    ????????suite.addTestSuite(TestPhoneGroup.
    class);
    ????????
    //$JUnit-END$
    ????????return?suite;
    ????}

    }


    import?junit.framework.TestCase;

    public?class?TestPhone?extends?TestCase?{
    ????
    private?Phone?phone;

    ????
    protected?void?setUp()?throws?Exception?{
    ????????phone?
    =?new?Phone(13888816666L);
    ????}

    ????
    public?void?testGetNumber()?{
    ????????assertEquals(
    13888816666L,?phone.getNumber());
    ????}

    ????
    public?void?testSetPhoneGroup()?{
    ????????PhoneGroup?guilin?
    =?new?PhoneGroup("桂林");
    ????????PhoneGroup?beijin?
    =?new?PhoneGroup("北京");
    ????????phone.setPhoneGroup(guilin);
    ????????phone.setPhoneGroup(beijin);

    ????????assertEquals(beijin,?phone.getPhoneGroup());
    ????????assertEquals(phone,?beijin.getPhones().iterator().next());
    ????????assertEquals(
    false,?guilin.getPhones().iterator().hasNext());
    ????}

    }


    import?junit.framework.TestCase;

    public?class?TestPhoneGroup?extends?TestCase?{
    ????
    private?PhoneGroup?group;

    ????
    protected?void?setUp()?throws?Exception?{
    ????????group?
    =?new?PhoneGroup("桂林");
    ????}

    ????
    public?void?testGetName()?{
    ????????assertEquals(
    "桂林",?group.getName());
    ????}

    ????
    public?void?testAddPhone_GetPhones()?{
    ????????Phone?p1?
    =?new?Phone(13888813331L);
    ????????Phone?p2?
    =?new?Phone(13888813332L);
    ????????Phone?p2_same?
    =?new?Phone(13888813332L);

    ????????assertEquals(
    true,?group.addPhone(p1));
    ????????assertEquals(
    false,?group.addPhone(p1));
    ????????assertEquals(
    true,?group.addPhone(p2));
    ????????assertEquals(
    false,?group.addPhone(p2_same));

    ????????assertEquals(
    2,?group.getPhones().size());
    ????????assertEquals(group,?p1.getPhoneGroup());
    ????????assertEquals(group,?p2.getPhoneGroup());
    ????}

    ????
    public?void?testRemovePhone()?{
    ????????Phone?p1?
    =?new?Phone(13888813331L);
    ????????assertEquals(
    true,?group.addPhone(p1));
    ????????assertEquals(
    true,?group.removePhone(p1.getNumber()));
    ????????assertEquals(
    0,?group.getPhones().size());
    ????????assertEquals(PhoneGroup.NONE,?p1.getPhoneGroup());

    ????????assertEquals(
    false,?group.removePhone(p1.getNumber()));
    ????}

    }


    import?junit.framework.TestCase;

    /**
    ?*?
    @author?chengang?2006-4-13
    ?
    */
    public?class?TestPhoneManager?extends?TestCase?{
    ????
    private?PhoneManager?mgr;

    ????@Override
    ????
    protected?void?setUp()?throws?Exception?{
    ????????mgr?
    =?PhoneManager.getInstance();
    ????}

    ????@Override
    ????
    protected?void?tearDown()?throws?Exception?{
    ????????mgr.clear();
    ????}

    ????
    public?void?testAddPhone()?{
    ????????Phone?phone?
    =?new?Phone(13888816666L);
    ????????assertEquals(
    true,?mgr.addPhone(phone));
    ????????assertEquals(
    1,?mgr.getPhones().size());
    ????????assertEquals(phone,?mgr.getPhone(
    13888816666L));
    ????}

    ????
    public?void?testAddPhoneGroup()?{
    ????????PhoneGroup?group?
    =?new?PhoneGroup("杭州");
    ????????assertEquals(
    true,?mgr.addPhoneGroup(group));
    ????????assertEquals(
    1,?mgr.getPhoneGroups().size());
    ????????assertEquals(group,?mgr.getPhoneGroup(
    "杭州"));
    ????}

    ????
    public?void?testAddNullPhone()?{
    ????????mgr.addPhone(
    null);
    ????????assertEquals(
    0,?mgr.getPhones().size());
    ????}

    ????
    public?void?testAddNullPhoneGroup()?{
    ????????mgr.addPhoneGroup(
    null);
    ????????assertEquals(
    0,?mgr.getPhoneGroups().size());
    ????}

    ????
    public?void?testAddPhoneForSameNumber()?{
    ????????Phone?phone1?
    =?new?Phone(13888816666L);
    ????????Phone?phone2?
    =?new?Phone(13888816666L);
    ????????assertEquals(
    true,?mgr.addPhone(phone1));
    ????????assertEquals(
    false,?mgr.addPhone(phone2));
    ????????assertEquals(
    1,?mgr.getPhones().size());
    ????????assertEquals(phone1,?mgr.getPhone(
    13888816666L));
    ????}

    ????
    public?void?testAddPhoneGroupForSameName()?{
    ????????PhoneGroup?g1?
    =?new?PhoneGroup("桂林");
    ????????PhoneGroup?g2?
    =?new?PhoneGroup("桂林");
    ????????assertEquals(
    true,?mgr.addPhoneGroup(g1));
    ????????assertEquals(
    false,?mgr.addPhoneGroup(g2));
    ????????assertEquals(
    1,?mgr.getPhoneGroups().size());
    ????????assertEquals(g1,?mgr.getPhoneGroup(
    "桂林"));
    ????}

    ????
    public?void?testRemovePhone()?{
    ????????Phone?phone1?
    =?new?Phone(13888816666L);
    ????????mgr.addPhone(phone1);
    ????????assertEquals(
    true,?mgr.removePhone(13888816666L));
    ????????assertEquals(
    null,?mgr.getPhone(13888816666L));
    ????}

    ????
    public?void?testRemovePhoneGroup()?{
    ????????PhoneGroup?g1?
    =?new?PhoneGroup("桂林");
    ????????mgr.addPhoneGroup(g1);
    ????????assertEquals(
    true,?mgr.removePhoneGroup("桂林"));
    ????????assertEquals(
    null,?mgr.getPhoneGroup("桂林"));
    ????}

    ????
    public?void?testRemoveNonePhone()?{
    ????????assertEquals(
    false,?mgr.removePhone(13888816666L));
    ????}

    ????
    public?void?testRemoveNonePhoneGroup()?{
    ????????assertEquals(
    false,?mgr.removePhoneGroup("sss"));
    ????}

    ????
    /**
    ?????*?測試,當新增一個Phone時,同時將其所屬PhoneGroup加入到PhoneManager中
    ?????
    */
    ????
    public?void?testAddPhoneThenAddGroup()?{
    ????????Phone?phone1?
    =?new?Phone(13888816661L);
    ????????Phone?phone2?
    =?new?Phone(13888816662L);
    ????????PhoneGroup?g1?
    =?new?PhoneGroup("桂林");
    ????????PhoneGroup?g2?
    =?new?PhoneGroup("桂林");
    ????????phone1.setPhoneGroup(g1);
    ????????phone2.setPhoneGroup(g2);
    ????????mgr.addPhone(phone1);
    ????????mgr.addPhone(phone2);
    ????????assertEquals(
    1,?mgr.getPhoneGroups().size());
    ????????assertEquals(phone1.getPhoneGroup(),?mgr.getPhoneGroup(
    "桂林"));

    ????????
    //Phone默認屬于PhoneGroup.NULL組
    ????????Phone?phone3?=?new?Phone(13888816663L);
    ????????Phone?phone4?
    =?new?Phone(13888816664L);
    ????????mgr.addPhone(phone3);
    ????????mgr.addPhone(phone4);
    ????????assertEquals(
    2,?mgr.getPhoneGroups().size());
    ????????assertEquals(PhoneGroup.NONE,?mgr.getPhoneGroup(PhoneGroup.NONE.getName()));
    ????}
    }


    /**
    ?*?
    @author?chengang?2006-4-13
    ?
    */
    public?class?Phone?{
    ????
    private?long?number;
    ????
    private?PhoneGroup?group;

    ????
    public?Phone(long?number)?{
    ????????
    this.number?=?number;
    ????????setPhoneGroup(PhoneGroup.NONE);
    ????}

    ????
    public?long?getNumber()?{
    ????????
    return?number;
    ????}

    ????
    /**
    ?????*?設置所屬PhoneGroup,并加入到PhoneGroup之下
    ?????*?
    @param?g
    ?????
    */
    ????
    public?void?setPhoneGroup(PhoneGroup?g)?{
    ????????
    if?(g?==?null)//過濾null
    ????????????g?=?PhoneGroup.NONE;

    ????????
    if?(group?==?g)
    ????????????
    return;

    ????????
    if?(group?!=?null)
    ????????????group.removePhone(number);
    //從舊組里刪除
    ????????group?=?g;
    ????????group.addPhone(
    this);//加入到新組中
    ????}

    ????
    public?PhoneGroup?getPhoneGroup()?{
    ????????
    return?group;
    ????}

    }


    import?java.util.Collections;
    import?java.util.HashSet;
    import?java.util.Set;

    public?class?PhoneGroup?{
    ????
    public?static?PhoneGroup?NONE?=?new?PhoneGroup("NONE");
    ????
    private?String?name;
    ????
    private?Set<Phone>?phones?=?new?HashSet<Phone>();

    ????
    public?PhoneGroup(String?name)?{
    ????????
    this.name?=?name;
    ????}

    ????
    public?String?getName()?{
    ????????
    return?name;
    ????}

    ????
    public?Set<Phone>?getPhones()?{
    ????????
    return?Collections.unmodifiableSet(phones);
    ????}

    ????
    /**
    ?????*?加入一個Phone,同時將Phone所屬組設為自己
    ?????*?
    @param?phone
    ?????*?
    @return
    ?????
    */
    ????
    public?boolean?addPhone(Phone?phone)?{
    ????????
    if?(phone?==?null)
    ????????????
    return?false;
    ????????
    if?(getPhone(phone.getNumber())?!=?null)//已存在同一號碼的Phone
    ????????????return?false;

    ????????
    if?(this?!=?phone.getPhoneGroup())?//如果本來就一樣,就沒必要設置了
    ????????????phone.setPhoneGroup(this);

    ????????phones.add(phone);
    ????????
    return?true;
    ????}

    ????
    public?Phone?getPhone(long?number)?{
    ????????
    for?(Phone?phone?:?phones)?{
    ????????????
    if?(phone.getNumber()?==?number)?{
    ????????????????
    return?phone;
    ????????????}
    ????????}
    ????????
    return?null;
    ????}

    ????
    /**
    ?????*?根據手機號刪除一個Phone,同時將此Phone的所屬組設為null
    ?????*?
    @param?number
    ?????*?
    @return
    ?????
    */
    ????
    public?boolean?removePhone(long?number)?{
    ????????Phone?phone?
    =?getPhone(number);
    ????????
    boolean?success?=?phones.remove(phone);
    ????????
    if?(success)
    ????????????phone.setPhoneGroup(
    null);
    ????????
    return?success;
    ????}
    }


    import?java.util.Collections;
    import?java.util.HashSet;
    import?java.util.Set;

    /**
    ?*?
    @author?chengang?2006-4-13
    ?
    */
    public?class?PhoneManager?{

    ????
    private?static?PhoneManager?instance?=?new?PhoneManager();
    ????
    private?Set<Phone>?phones?=?new?HashSet<Phone>();
    ????
    private?Set<PhoneGroup>?groups?=?new?HashSet<PhoneGroup>();

    ????
    private?PhoneManager()?{}

    ????
    public?static?PhoneManager?getInstance()?{
    ????????
    return?instance;
    ????}

    ????
    public?boolean?addPhone(Phone?phone)?{
    ????????
    if?(phone?==?null)
    ????????????
    return?false;
    ????????
    if?(getPhone(phone.getNumber())?!=?null)//已存在同一號碼的Phone
    ????????????return?false;

    ????????PhoneGroup?g?
    =?phone.getPhoneGroup();
    ????????addPhoneGroup(g);
    ????????
    return?phones.add(phone);
    ????}

    ????
    public?Set<Phone>?getPhones()?{
    ????????
    return?Collections.unmodifiableSet(phones);
    ????}

    ????
    public?Phone?getPhone(long?number)?{
    ????????
    for?(Phone?phone?:?phones)?{
    ????????????
    if?(phone.getNumber()?==?number)?{
    ????????????????
    return?phone;
    ????????????}
    ????????}
    ????????
    return?null;
    ????}

    ????
    public?void?clear()?{
    ????????phones.clear();
    ????????groups.clear();
    ????}

    ????
    public?boolean?removePhone(long?number)?{
    ????????Phone?phone?
    =?getPhone(number);
    ????????
    return?phones.remove(phone);
    ????}

    ????
    public?boolean?removePhoneGroup(String?name)?{
    ????????PhoneGroup?group?
    =?getPhoneGroup(name);
    ????????
    return?groups.remove(group);
    ????}

    ????
    /**
    ?????*?加入一個組</P>
    ?????*?如果group=null,加入失敗并返回false;如果已存在組名相同的組,加失敗并返回false;
    ?????*?
    @param?group
    ?????*?
    @return
    ?????
    */
    ????
    public?boolean?addPhoneGroup(PhoneGroup?group)?{
    ????????
    if?(group?==?null)
    ????????????
    return?false;
    ????????
    if?(getPhoneGroup(group.getName())?!=?null)//已存在同一號碼的Phone
    ????????????return?false;
    ????????
    return?groups.add(group);
    ????}

    ????
    public?Set<PhoneGroup>?getPhoneGroups()?{
    ????????
    return?Collections.unmodifiableSet(groups);
    ????}

    ????
    public?PhoneGroup?getPhoneGroup(String?name)?{
    ????????
    for?(PhoneGroup?group?:?groups)?{
    ????????????
    if?(group.getName()?==?name)?{
    ????????????????
    return?group;
    ????????????}
    ????????}
    ????????
    return?null;
    ????}

    }



    作者簡介

    陳剛,廣西桂林人,著作有《Eclipse從入門到精通》
    您可以通過其博客了解更多信息和文章:http://www.ChenGang.com.cn
    版權聲明:本博客所有文章僅適用于非商業性轉載,并請在轉載時注明出處及作者的署名

    posted on 2006-04-13 23:15 Vincent.Chen 閱讀(329) 評論(0)  編輯  收藏 所屬分類: Java

    主站蜘蛛池模板: 国产精品1024在线永久免费| 精品成人一区二区三区免费视频 | 伊人久久大香线蕉亚洲| 黄色网址在线免费| 亚洲国产91在线| 又粗又大又猛又爽免费视频| 最近免费字幕中文大全| 亚洲一级在线观看| 亚洲精品综合久久| 最近2019中文字幕免费直播 | 女人体1963午夜免费视频| 亚洲va精品中文字幕| 亚洲自偷自偷偷色无码中文| 国产在线观看麻豆91精品免费 | 中文字幕乱码系列免费| 精品亚洲成A人无码成A在线观看| 亚洲一区视频在线播放| 青青在线久青草免费观看| jizz在线免费播放| 涩涩色中文综合亚洲| 国产亚洲一区二区三区在线观看| 成年女人毛片免费播放人| 日韩a级无码免费视频| 丰满亚洲大尺度无码无码专线| 亚洲成a人片77777老司机| 国产中文字幕免费观看| 99国产精品永久免费视频| 两个人看的www高清免费观看| 亚洲国产成人无码AV在线| 亚洲高清在线播放| 亚洲精品97久久中文字幕无码| 中文字幕无码免费久久99| 久久国产精品免费看| h视频在线免费观看| 亚洲国产精品网站在线播放| 亚洲系列中文字幕| 亚洲av永久无码精品表情包| 亚洲精品一级无码中文字幕| 女人张开腿给人桶免费视频| 手机在线看永久av片免费| 亚洲黄色免费网站|