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 閱讀(339) 評論(0)  編輯  收藏 所屬分類: Java

          主站蜘蛛池模板: 井陉县| 剑河县| 泌阳县| 德化县| 盐边县| 潞西市| 仁化县| 涡阳县| 泰顺县| 临高县| 车险| 石台县| 咸宁市| 德阳市| 洛川县| 剑川县| 丰宁| 雷山县| 新野县| 泰宁县| 正定县| 陇川县| 肥城市| 福海县| 马龙县| 江源县| 灌阳县| 太谷县| 景洪市| 香河县| 治县。| 定州市| 夏邑县| 化州市| 太白县| 西畴县| 若羌县| 彩票| 成安县| 乐东| 黄大仙区|