爲你的程序錦上添花的五種程序組織形式

形式一."見兔撒鷹".

如果有一個類有一個集合成員,可以在爲此成員添加元素時再把具體集合建立起來,以免浪費空間和時間.

例:

1publicclassCompany{
2privateListmembers=null
;
3

4publicvoidaddMember(Membermember){
5if(members=null
){
6members=new
ArrayList();
7
}
8

9members.add(member);
10
}
11
}
12

異曲同工的另外一個例子:

1publicclassSingleton{
2privatestaticSingletoninstance=null
;
3

4publicstaticsynchronizedSingletongetInstance(){
5//要用的時候再把Singleton建立起來

6if(instance==null){
7instance=new
Singleton();
8
}
9

10returninstance;
11
}
12
}
13

形式二."只管結果,不顧過程"

從集合中取區間元素時,可以直接從上下限之間取來,讓try...catch...去處理越界的事.

題設:有個數不定元素的列表(allTodoes),需要從中取N個,起始位置不限,你怎麼編寫程序.

很多人開始進行越界的判斷,出來一堆if else,有時還需要在紙上寫好思路,完畢後還有多方測試,生怕出錯,即使編寫好後其他人維護起來也是小心翼翼的.其實沒必要這麼麻煩.

例.

1intstart=pageIndex*pageSize;
2intend=start+
pageSize;
3

4for(inti=start;i<end;i++
){
5try
{
6
todoResult.addTodo((Todo)allTodoes.get(i));
7
}
8catch
(Exceptionex){
9continue
;
10
}
11}

題外話:分支和循環語句天生就不容易理解,尤其是在嵌套較深的時候,因爲這是機器的思維特性.還是try...catch...比較貼近人類思維.


形式三."奉旨行事"
在查詢中,如果把查詢條件和遴選過程分開來更有益,程序也因此解耦合.這纔是OO化的查詢.

需求:從公司的職員列表中,找出男性且年齡大於22的成員.

傳統寫法:

1Listallmembers=company.getMembers();//取得所有成員
2Listresults=newArrayList();//結果列表
3
4for(Iteratorit=
allmembers.iterator();it.hasNext();){
5Membermember=
(Member)it.next();
6

7if(member.getAge()>22&&member.isMale()){//篩選,這裏是把查詢條件和遴選過程融合在一起,條件一變立即就得加個分支.

8results.add(member);
9
}
10
}
11

這種寫法沒有錯,但是不是面向對象的寫法,它有以下缺陷:
1.查詢條件和篩選過程沒有分離.
2.這樣寫的後果使Company變成了一個失血模型而不是領域模型.
3.換查詢條件的話,上面除了"篩選"一句有變化外其它都是模板代碼,重複性很高.

真正符合OO的查詢應該是這樣:

1MemberFilterfilter1=newMemberFilter(){
2publicboolean
accept(Membermember){
3returnmember.isMale()&&member.getAge()>22
;
4
}
5
};
6

7Listls=company.listMembers(filter1);

這段代碼成功的把查詢條件作爲一個接口分離了出去,接口代碼如下:

1publicinterfaceMemberFilter{
2publicboolean
accept(Membermember);
3}

而類Company增加了這樣一個函數:

1publicListlistMembers(MemberFiltermemberFilter){
2Listretval=new
ArrayList();
3

4for(Iteratorit=
members.iterator();it.hasNext();){
5Membermember=
(Member)it.next();
6

7if
(memberFilter.accept(member)){
8
retval.add(member);
9
}
10
}
11

12return
retval;
13}

這就把模板代碼歸結到了類內部,外面不會重複書寫了.Company也同時擁有了數據和行爲,而不是原來的數據容器了.

形式四."化繁爲簡"
這種結構將多個分支語句變換爲一個查表結構,這樣做對擴充程序結構,修改具體數額都很方便,使程序更易於維護.還可以把歸結出的表結構放在持久介質中如XML文件,數據庫等,用到的時候再取,這樣做在條件變化時不需要修改程序.

原始代碼(VB代碼,但應該不妨礙理解):

1Dimcount1
2count1=salary.Value+USA.Value*Drate+JAN.Value*Jrate-4000

3Ifcount1<500Then

4tax.Value=count1*0.05

5ElseIfcount1<2000Then

6tax.Value=count1*0.1-25

7ElseIfcount1<5000Then

8tax.Value=count1*0.15-125

9ElseIfcount1<20000Then

10tax.Value=count1*0.2-375

11ElseIfcount1<40000Then

12tax.Value=count1*0.25-1375

13ElseIfcount1<60000Then

14tax.Value=count1*0.3-3375

15Else

16tax.Value=count1*0.3-3375

17EndIf

變換如下:
這是個稅率計算的語句段,公式是確定的:稅=月薪*稅率-折扣,稅率又和月薪有關係,月薪越高稅率越高,首先這裏可以歸納出一個基本類:

1publicclassTaxItem{
2floatlimit;//月薪界限

3floatratio;//稅率
4floatdiscount;//折扣
5
6publicTaxItem(floatlimit,floatratio,floatdiscount){
7this.limit=
limit;
8this.ratio=
ratio;
9this.discount=
discount;
10
}
11

12publicTaxItem(){
13this(0.0f,0.0f,0.0f
);
14
}
15

16publicfloatgetDiscount(){
17return
discount;
18
}
19

20publicfloatgetLimit(){
21return
limit;
22
}
23

24publicfloatgetRatio(){
25return
ratio;
26
}
27
}
28

29


然後就是稅計算類:

1publicclassTaxCaculator{
2privatestaticArrayListlist=new
ArrayList();
3

4public
TaxCaculator(){
5//這裏把各個等級加入到鏈表中,注意添加順序是由小到大

6list.add(newTaxItem(500.0f,0.05f,0.0f));
7list.add(newTaxItem(2000.0f,0.1f,25.0f
));
8list.add(newTaxItem(5000.0f,0.15f,125.0f
));
9list.add(newTaxItem(20000.0f,0.2f,375.0f
));
10list.add(newTaxItem(40000.0f,0.25f,1375.0f
));
11list.add(newTaxItem(60000.0f,0.3f,3375.0f
));
12
}
13

14//這個函數用來計算所得稅

15publicfloatgetTax(floatsalary){
16TaxItemitem=new
TaxItem();
17

18for(inti=0;i<list.size();i++
){
19item=
(TaxItem)list.get(i);
20

21if(salary>
item.getLimit()){
22continue
;
23
}
24else
{
25break
;
26
}
27
}
28

29//返回最終結果,當然,這個公式也可以放在TaxItem類中,這裏就見仁見智了。

30returnsalary*item.getRatio()-item.getDiscount();
31
}
32}



調用如下:

1TaxCaculatortaxCaculator=newTaxCaculator();
2

3floatsalary=1000
.f;
4System.out.println("Salary="+salary+"Tax="+
taxCaculator.getTax(salary));
5

6salary=2000
.f;
7System.out.println("Salary="+salary+"Tax="+
taxCaculator.getTax(salary));
8

9salary=3000
.f;
10System.out.println("Salary="+salary+"Tax="+taxCaculator.getTax(salary));


形式五."分而治之"
該結構將分支語句的執行部分分散到單獨的類中處理,降低了系統耦合度,程序也更容易維護.

舉例如下:
在日常工作中,我們經常需要解析一段字符串並交由相應的函數進行處理,例如TCP/IP通信中的命令解析和用戶自定義文件解析等場合,通常的處理方法是這樣:

if(命令==”AAA”){
函數AAA執行;
}
else if(命令==”BBB”){
函數BBB執行;
}
.
.
.
else{
函數XXX執行;
}

這種方法在命令較少時是有效的,當命令衆多時,if語句和相關的函數將會形成一個巨集,給檢查,維護和擴充帶來了很大的不便,久而久之將會成爲系統性能提升的瓶頸。

一個成功的軟件程序必須儘可能簡單並易於重構和擴展,在命令模式和Java反射機制的幫助下,我們可以從容解決上述問題,達到簡單並易於重構和擴展的要求。以下將簡要說明解決方案。

1. 製作一個命令的抽象接口.

1publicinterfaceCommand{
2publicabstractvoid
execute(String[]args);
3}

2. 讓每種命令都實現這個接口.

1//命令一
2publicclassCommandType01implementsCommand{
3publicvoid
execute(String[]args){
4System.out.println("\ncommandType01start!"
);
5System.out.print("\tcommandType01Length="+
args.length);
6System.out.println("\ncommandType01End!"
);
7
}
8
}
9

10//命令二
11publicclassCommandType02implementsCommand{
12publicvoid
execute(String[]args){
13System.out.println("\ncommandType02start!"
);
14

15System.out.print("\tcommandType02is:"
);
16for
(Stringitem:args){
17System.out.print("\t"+
item);
18
}
19

20System.out.println("\ncommandType02End!"
);
21
}
22
}
23

24//命令三
25publicclassCommandType03implementsCommand{
26publicvoid
execute(String[]args){
27System.out.println("\ncommandType03start!"
);
28System.out.print("\tcommandType03lastNation="+args[args.length-1
]);
29System.out.println("\ncommandType03End!"
);
30
}
31
}
32

33


讓每種命令都實現execute接口的用意是強制每個命令的執行方式一致,簡化調用時的處理,但執行內容應該根據實際情況決定.
例如
命令一的執行內容是輸出參數的個數
命令二的執行內容是輸出參數的內容
命令三的執行內容是輸出最後一個參數

3. 將命令防置到命令中心中去
命令中心類的代碼如下:

1publicclassMediation{
2Commandcmmd;//命令對象的引用

3String[]cmmdArgs;//參數列表
4
5public
Mediation(){
6

7
}
8

9publicvoid
fetchCommand(StringstrCmmd){
10cmmdArgs=strCmmd.split("\s+");//分析原始命令

11
12StringclassName="Command"+cmmdArgs[0];//根據分析後命令的第一個參數得到類名

13
14try
發佈了27 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章