形式一."見兔撒鷹". 例: 1 public class Company{
2 private List members=null; 3 4 public void addMember(Member member){ 5 if(members=null){ 6 members=new ArrayList(); 7 } 8 9 members.add(member); 10 } 11 } 12 |
|
異曲同工的另外一個例子: 1 public class Singleton{
2 private static Singleton instance=null; 3 4 public static synchronized Singleton getInstance(){ 5 // 要用的時候再把Singleton建立起來 6 if(instance==null){ 7 instance=new Singleton(); 8 } 9 10 return instance; 11 } 12 } 13 形式二."只管結果,不顧過程" 題設:有個數不定元素的列表(allTodoes),需要從中取N個,起始位置不限,你怎麼編寫程序. 很多人開始進行越界的判斷,出來一堆if else,有時還需要在紙上寫好思路,完畢後還有多方測試,生怕出錯,即使編寫好後其他人維護起來也是小心翼翼的.其實沒必要這麼麻煩. 例. 1 int start=pageIndex*pageSize;
2 int end=start+pageSize; 3 4 for(int i=start;i<end;i++){ 5 try{ 6 todoResult.addTodo((Todo)allTodoes.get(i)); 7 } 8 catch(Exception ex){ 9 continue; 10 } 11 } 題外話:分支和循環語句天生就不容易理解,尤其是在嵌套較深的時候,因爲這是機器的思維特性.還是try...catch...比較貼近人類思維.
需求:從公司的職員列表中,找出男性且年齡大於22的成員. 傳統寫法: 1 List allmembers=company.getMembers();// 取得所有成員
2 List results=new ArrayList();// 結果列表 3 4 for(Iterator it=allmembers.iterator();it.hasNext();){ 5 Member member=(Member)it.next(); 6 7 if(member.getAge()>22 && member.isMale()){ // 篩選,這裏是把查詢條件和遴選過程融合在一起,條件一變立即就得加個分支. 8 results.add(member); 9 } 10 } 11
這種寫法沒有錯,但是不是面向對象的寫法,它有以下缺陷: 真正符合OO的查詢應該是這樣: 1 MemberFilter filter1=new MemberFilter(){
2 public boolean accept(Member member) { 3 return member.isMale() && member.getAge()>22; 4 } 5 }; 6 7 List ls=company.listMembers(filter1);
這段代碼成功的把查詢條件作爲一個接口分離了出去,接口代碼如下: 1 public interface MemberFilter{
2 public boolean accept(Member member); 3 } 而類Company增加了這樣一個函數: 1 public List listMembers(MemberFilter memberFilter){
2 List retval=new ArrayList(); 3 4 for(Iterator it=members.iterator();it.hasNext();){ 5 Member member=(Member)it.next(); 6 7 if(memberFilter.accept(member)){ 8 retval.add(member); 9 } 10 } 11 12 return retval; 13 } 這就把模板代碼歸結到了類內部,外面不會重複書寫了.Company也同時擁有了數據和行爲,而不是原來的數據容器了. 形式四."化繁爲簡" 原始代碼(VB代碼,但應該不妨礙理解): 1 Dim count1
2 count1 = salary.Value + USA.Value * Drate + JAN.Value * Jrate - 4000 3 If count1 < 500 Then 4 tax.Value = count1 * 0.05 5 ElseIf count1 < 2000 Then 6 tax.Value = count1 * 0.1 - 25 7 ElseIf count1 < 5000 Then 8 tax.Value = count1 * 0.15 - 125 9 ElseIf count1 < 20000 Then 10 tax.Value = count1 * 0.2 - 375 11 ElseIf count1 < 40000 Then 12 tax.Value = count1 * 0.25 - 1375 13 ElseIf count1 < 60000 Then 14 tax.Value = count1 * 0.3 - 3375 15 Else 16 tax.Value = count1 * 0.3 - 3375 17 End If 變換如下: 1 public class TaxItem{
2 float limit; // 月薪界限 3 float ratio;// 稅率 4 float discount;// 折扣 5 6 public TaxItem(float limit,float ratio,float discount){ 7 this.limit=limit; 8 this.ratio=ratio; 9 this.discount=discount; 10 } 11 12 public TaxItem(){ 13 this(0.0f,0.0f,0.0f); 14 } 15 16 public float getDiscount() { 17 return discount; 18 } 19 20 public float getLimit() { 21 return limit; 22 } 23 24 public float getRatio() { 25 return ratio; 26 } 27 } 28 29
1 public class TaxCaculator{
2 private static ArrayList list=new ArrayList(); 3 4 public TaxCaculator(){ 5 // 這裏把各個等級加入到鏈表中,注意添加順序是由小到大 6 list.add(new TaxItem(500.0f,0.05f,0.0f)); 7 list.add(new TaxItem(2000.0f,0.1f,25.0f)); 8 list.add(new TaxItem(5000.0f,0.15f,125.0f)); 9 list.add(new TaxItem(20000.0f,0.2f,375.0f)); 10 list.add(new TaxItem(40000.0f,0.25f,1375.0f)); 11 list.add(new TaxItem(60000.0f,0.3f,3375.0f)); 12 } 13 14 // 這個函數用來計算所得稅 15 public float getTax(float salary){ 16 TaxItem item=new TaxItem(); 17 18 for(int i=0;i<list.size();i++){ 19 item=(TaxItem)list.get(i); 20 21 if(salary>item.getLimit()){ 22 continue; 23 } 24 else{ 25 break; 26 } 27 } 28 29 // 返回最終結果,當然,這個公式也可以放在TaxItem 類中,這裏就見仁見智了。 30 return salary*item.getRatio()-item.getDiscount(); 31 } 32 }
1 TaxCaculator taxCaculator=new TaxCaculator();
2 3 float salary=1000.f; 4 System.out.println("Salary="+salary +" Tax="+taxCaculator.getTax(salary)); 5 6 salary=2000.f; 7 System.out.println("Salary="+salary +" Tax="+taxCaculator.getTax(salary)); 8 9 salary=3000.f; 10 System.out.println("Salary="+salary +" Tax="+taxCaculator.getTax(salary));
舉例如下: if(命令==”AAA”){ 這種方法在命令較少時是有效的,當命令衆多時,if語句和相關的函數將會形成一個巨集,給檢查,維護和擴充帶來了很大的不便,久而久之將會成爲系統性能提升的瓶頸。 一個成功的軟件程序必須儘可能簡單並易於重構和擴展,在命令模式和Java反射機制的幫助下,我們可以從容解決上述問題,達到簡單並易於重構和擴展的要求。以下將簡要說明解決方案。 1. 製作一個命令的抽象接口. 1 public interface Command{
2 public abstract void execute(String[] args); 3 }
2. 讓每種命令都實現這個接口. 1 // 命令一
2 public class CommandType01 implements Command{ 3 public void execute(String[] args){ 4 System.out.println("/n commandType01 start!"); 5 System.out.print("/t commandType01 Length="+args.length); 6 System.out.println("/n commandType01 End!"); 7 } 8 } 9 10 // 命令二 11 public class CommandType02 implements Command{ 12 public void execute(String[] args){ 13 System.out.println("/n commandType02 start!"); 14 15 System.out.print("/t commandType02 is:"); 16 for(String item:args){ 17 System.out.print("/t "+item); 18 } 19 20 System.out.println("/n commandType02 End!"); 21 } 22 } 23 24 // 命令三 25 public class CommandType03 implements Command{ 26 public void execute(String[] args){ 27 System.out.println("/n commandType03 start!"); 28 System.out.print("/t commandType03 last Nation="+args[args.length-1]); 29 System.out.println("/n commandType03 End!"); 30 } 31 } 32 33
3. 將命令防置到命令中心中去 1 public class Mediation{
2 Command cmmd;// 命令對象的引用 3 String[] cmmdArgs;// 參數列表 4 5 public Mediation(){ 6 7 } 8 9 public void fetchCommand(String strCmmd){ 10 cmmdArgs=strCmmd.split("/s+");// 分析原始命令 11 12 String className="Command"+cmmdArgs[0];// 根據分析後命令的第一個參數得到類名 13 14 try{ 15 Class cls=Class.forName(className);// 利用反射機制得到類 16 cmmd=(Command)cls.newInstance();// 由類得到類實例 17 } 18 catch(Exception ex){ 19 ex.printStackTrace(); 20 } 21 } 22 23 24 public void executeCommand(){ 25 cmmd.execute(cmmdArgs);// 執行命令對象的execute方法 26 } 27 28 }
1 Mediation mediation = new Mediation();
2 // 取得命令一併執行 3 mediation.fetchCommand("Type01 AB CD"); 4 mediation.executeCommand(); 5 6 // 取得命令二並執行 7 mediation.fetchCommand("Type02 1 2 3 4"); 8 mediation.executeCommand(); 9 10 // 取得命令三並執行 11 mediation.fetchCommand("Type03 USA Russia China"); 12 mediation.executeCommand(); 13 執行效果如下: commandType02 start! commandType03 start! 由上可見,我們使用反射機制消除了龐大的分支語句,把命令的執行過程分散到了Command的各個子類中,降低了命令類和控制中心類的耦合程度,達到了簡單並易於重構和擴展的要求。如果新增一種命令,只需增加Command的一個子類就可以了。 注意:這裏對命令和Command的子類類名有特殊要求,即一種命令對應一種子類,子類類名可以由命令的首個參數簡單組合而來,否則還是避免不了分支語句。 以上五種組織形式,若加以靈活運用,相信能減少一些代碼臭味. |
爲你的程序錦上添花的五種程序組織形式
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.