和風細雨

          世上本無難事,心以為難,斯乃真難。茍不存一難之見于心,則運用之術自出。

          從薪水計算的例子看一段程序在不同環(huán)境中的變化

          本例完整程序下載: http://www.aygfsteel.com/Files/sitinspring/TaxCaculator20071025203159.rar

          世界天天在變,程序也一樣,唯一不變的只有變化二字.現(xiàn)代程序應該隨著日新月異的環(huán)境而不斷變化,此之謂"物競天擇,適者生存",下面的例子就演示了這一變化過程.

          需求如下:(注:非真實稅率,僅僅是個例子)
              稅后薪水=月總收入×適用稅率-速算扣除數(shù)

          級 數(shù) 全月應納稅所得額 稅率(%)  稅率      速算扣除數(shù)
            1     不超過500元的                                 5%
            2     超過500元至2000元的部分              10%          25
            3     超過2000元至5000元的部分            15%         125
            4     超過5000元至20000元的部分          20%         375
            5     超過20000元的部分                          25%         1375


          如果讓你來為下列需求書寫一段代碼,你將如何處理


          1.過程式方法:
          如果說需求(稅率和扣除數(shù))在較長一段時間內(nèi)不會變化,也就是說需求變化時,程序生命已經(jīng)結束,我們可以使用傳統(tǒng)的分支語句來編碼,程序?qū)懗鰜順O簡單.

          package com.sitinspring.processstyle;

          /**
           * Main函數(shù)所在的類
           * 
          @author sitinspring(junglesong@gmail.com)
           *
           
          */

          public class Main{
              
          public static void main(String[] args){        
                  
          for(double total=100;total<30000;total+=1000){
                      System.out.println(
          "稅前薪水="+total+" 稅后薪水="+getSalary(total));
                  }
                  
              }

              
              
          // 傳統(tǒng)的過程式計算方法
              public static double getSalary(double total){
                  
          double retval;
                  
                  
          if(total < 500){
                      retval
          =total*(1-0.05);
                  }

                  
          else if(total < 2000){
                      retval
          =total*(1-0.1)-25;
                  }

                  
          else if(total < 5000){
                      retval
          =total*(1-0.15)-125;
                  }

                  
          else if(total < 20000){
                      retval
          =total *(1-0.20)-375;
                  }

                  
          else{
                      retval
          =total *(1-0.25)-1375;
                  }


                  
          return retval;
              }

          }

          2.OO化的方法
          但是如果說需求(稅率和扣除數(shù))在軟件生命已經(jīng)結束前是有可能變化的,或者說變化不可預期,用戶一定程序上也希望自己修改,IF分支的結構將不再適用,但程序可以停止,這時就應該把分支語句OO化,將規(guī)則和數(shù)據(jù)分離開來可以了,至于數(shù)據(jù)是固化在程序中還是啟動時載入可以視情況確定,例子中采取了固化的方式,一般來說用XML文件記錄數(shù)據(jù)較好,改起來很方便.

          Main類:
          package com.sitinspring.oostyle;

          /**
           * Main函數(shù)所在的類
           * 
          @author sitinspring(junglesong@gmail.com)
           *
           
          */

          public class Main{
              
          public static void main(String[] args){    
                  SalaryCaculator caculator
          =new SalaryCaculator();
                  
                  
          for(double total=100;total<30000;total+=1000){
                      System.out.println(
          "稅前薪水="+total+" 稅后薪水="+caculator.getSalaryAfterTax(total));
                  }
                  
              }

          }

          SalaryCaculator類(其中99999999表示極大值,一般收入都小于這個值):
          package com.sitinspring.oostyle;

          import java.util.ArrayList;
          import java.util.Iterator;
          import java.util.List;

          /**
           * 工資計算類
           * 
          @author sitinspring(junglesong@gmail.com)
           *
           
          */

          public class SalaryCaculator{
              
          private List<SalaryGrade> grades;
              
              
              
          public SalaryCaculator(){
                  grades
          =new ArrayList<SalaryGrade>();
                  
                  grades.add(
          new SalaryGrade(500,0.05,0));
                  grades.add(
          new SalaryGrade(2000,0.1,25));
                  grades.add(
          new SalaryGrade(5000,0.15,125));
                  grades.add(
          new SalaryGrade(20000,0.20,375));
                  grades.add(
          new SalaryGrade(99999999,0.25,1375));
              }

              
              
          // OO化的查詢方法
              public double getSalaryAfterTax(double total){
                  SalaryGrade taxGrade
          =null;
                  
                  
          for(Iterator it=grades.iterator();it.hasNext();){
                      taxGrade
          =(SalaryGrade)it.next();
                      
                      
          if(total>taxGrade.getGrade()){
                          
          continue;
                      }

                      
          else{
                          
          break;
                      }

                  }

                  
                  
          return total*(1-taxGrade.getRatio())-taxGrade.getDiscount();
              }

          }

          SalaryGrade類:
          package com.sitinspring.oostyle;

          /**
           * 工資等級類
           * 
          @author sitinspring(junglesong@gmail.com)
           *
           
          */

          public class SalaryGrade {
              
          // 月薪界限
              private double grade;

              
          // 稅率
              private double ratio;

              
          // 折扣
              private double discount;

              
          public SalaryGrade(double grade, double ratio, double discount) {
                  
          this.grade = grade;
                  
          this.ratio = ratio;
                  
          this.discount = discount;
              }


              
          public SalaryGrade() {
                  
          this(0.0f0.0f0.0f);
              }


              
          public double getDiscount() {
                  
          return discount;
              }


              
          public double getGrade() {
                  
          return grade;
              }


              
          public double getRatio() {
                  
          return ratio;
              }

          }

          3.線程安全的OO方法
          如果說需求(稅率和扣除數(shù))是人為動態(tài)指定的,且整個系統(tǒng)是7*24小時的系統(tǒng),一般不允許停機.這樣的情況下要求程序具有熱插拔的能力,這時,我們必須加上一個讀寫鎖才能解決問題.

          Main類:
          package com.sitinspring.dynamicoostyle;

          import java.util.ArrayList;
          import java.util.List;

          import com.sitinspring.oostyle.SalaryGrade;

          /**
           * Main函數(shù)所在的類
           * 
           * 
          @author sitinspring(junglesong@gmail.com)
           * 
           
          */

          public class Main {
              
          public static void main(String[] args) {
                  SalaryCaculator caculator 
          = new SalaryCaculator();
                  
                  List
          <SalaryGrade> grades1 = new ArrayList<SalaryGrade>();
                  grades1.add(
          new SalaryGrade(5000.050));
                  grades1.add(
          new SalaryGrade(20000.125));
                  grades1.add(
          new SalaryGrade(50000.15125));
                  grades1.add(
          new SalaryGrade(200000.20375));
                  grades1.add(
          new SalaryGrade(999999990.251375));        
                  Writer writer1
          =new Writer(caculator,grades1);
                  
                  List
          <SalaryGrade> grades2 = new ArrayList<SalaryGrade>();
                  grades2.add(
          new SalaryGrade(50000.5125));
                  grades2.add(
          new SalaryGrade(999999990.91375));        
                  
                  Writer writer2
          =new Writer(caculator,grades2);

                  
          while (true{            
                      
          for (double total = 100; total < 30000; total += 1000{
                          sleep(
          1);
                          System.out.println(
          "稅前薪水=" + total + " 稅后薪水="
                                  
          + caculator.getSalaryAfterTax(total));
                      }

                  }

              }

              
              
          // 用于延時
              public static void sleep(int sleepSecond){
                  
          try{
                      Thread.sleep(sleepSecond
          *1000);
                  }

                  
          catch(Exception ex){
                      ex.printStackTrace();
                  }

              }

          }

          ReadWriteLock類:
          package com.sitinspring.dynamicoostyle;

          /**
           * 讀寫鎖,用于線程控制
           * 
          @author sitinspring(junglesong@gmail.com)
           *
           
          */

          public class ReadWriteLock{
              
          // 讀狀態(tài)
              private boolean isRead;
              
              
          // 寫狀態(tài)
              private boolean isWrite;
              
              
          public synchronized void readLock(){
                  
          // 有寫入時讀取線程停止
                  while(isWrite){
                      
          try{    
                          System.out.println(
          "有線程在進行寫入,讀取線程停止,進入等待狀態(tài)");
                          wait();
                      }

                      
          catch(InterruptedException ex){
                          ex.printStackTrace();
                      }

                  }

                  
                  System.out.println(
          "設定鎖為讀取狀態(tài)");
                  isRead
          =true;
              }

              
              
          public synchronized void readUnlock(){
                  System.out.println(
          "解除讀取鎖");
                  isRead
          =false;
                  notifyAll();
              }

              
              
          public synchronized void writeLock(){
                  
          // 有讀取時讀取線程停止
                  while(isRead){
                      
          try{    
                          System.out.println(
          "有線程在進行讀取,寫入線程停止,進入等待狀態(tài)");
                          wait();
                      }

                      
          catch(InterruptedException ex){
                          ex.printStackTrace();
                      }

                  }

                  
                  
          // 有寫入時寫入線程也一樣要停止
                  while(isWrite){
                      
          try{    
                          System.out.println(
          "有線程在進行寫入,寫入線程停止,進入等待狀態(tài)");
                          wait();
                      }

                      
          catch(InterruptedException ex){
                          ex.printStackTrace();
                      }

                  }

                  
                  System.out.println(
          "設定鎖為寫入狀態(tài)");
                  isWrite
          =true;
              }

              
              
          public synchronized void writeUnlock(){
                  System.out.println(
          "解除寫入鎖");
                  isWrite
          =false;
                  notifyAll();
              }

          }

          SalaryCaculator類:
          package com.sitinspring.dynamicoostyle;

          import java.util.ArrayList;
          import java.util.Iterator;
          import java.util.List;

          import com.sitinspring.oostyle.SalaryGrade;

          /**
           * 工資計算類
           * 
           * 
          @author sitinspring(junglesong@gmail.com)
           * 
           
          */

          public class SalaryCaculator {
              
          private List<SalaryGrade> grades;

              
          private ReadWriteLock readWriteLock;

              
          public SalaryCaculator() {
                  readWriteLock 
          = new ReadWriteLock();

                  grades 
          = new ArrayList<SalaryGrade>();

                  grades.add(
          new SalaryGrade(5000.050));
                  grades.add(
          new SalaryGrade(20000.125));
                  grades.add(
          new SalaryGrade(50000.15125));
                  grades.add(
          new SalaryGrade(200000.20375));
                  grades.add(
          new SalaryGrade(999999990.251375));
              }


              
          // 線程安全的,OO化的查詢方法
              public double getSalaryAfterTax(double total) {
                  
          try {
                      readWriteLock.readLock();

                      SalaryGrade taxGrade 
          = null;

                      
          for (Iterator it = grades.iterator(); it.hasNext();) {
                          taxGrade 
          = (SalaryGrade) it.next();

                          
          if (total > taxGrade.getGrade()) {
                              
          continue;
                          }
           else {
                              
          break;
                          }

                      }


                      
          return total * (1 - taxGrade.getRatio()) - taxGrade.getDiscount();
                  }
           finally {
                      readWriteLock.readUnlock();
                  }

              }


              
          public void setGrades(List<SalaryGrade> grades) {
                  
          try {
                      readWriteLock.writeLock();
                      
          this.grades = grades;
                  }
           finally {
                      readWriteLock.writeUnlock();
                  }

              }

          }

          Writer類(模擬人工寫入):
          package com.sitinspring.dynamicoostyle;

          import java.util.List;
          import java.util.Random;

          import com.sitinspring.oostyle.SalaryGrade;

          /**
           * 更新工資等級的線程
           * 
           * 
          @author sitinspring(junglesong@gmail.com)
           * 
           
          */

          public class Writer implements Runnable {
              
          private static final Random random = new Random();

              
          private SalaryCaculator caculator;

              
          private List<SalaryGrade> grades;

              
          public Writer(SalaryCaculator caculator, List<SalaryGrade> grades) {
                  
          this.caculator = caculator;
                  
          this.grades = grades;

                  Thread thread 
          = new Thread(this);
                  thread.start();
              }


              
          public void run() {
                  
          while (true{
                      
          try {
                          Thread.sleep(random.nextInt(
          3* 1000);
                      }
           catch (Exception ex) {
                          ex.printStackTrace();
                      }


                      caculator.setGrades(grades);
                  }

              }

          }

          雖然上述三段程序大小和復雜度各不一樣,但它們沒有優(yōu)劣之分,各自都是適應環(huán)境的產(chǎn)物,沒有一種程序結構能包打天下,但我們需要知道根據(jù)客觀情況選取不同的結構,這樣才能創(chuàng)造出優(yōu)秀的程序.

          以上

          posted on 2008-02-22 11:27 和風細雨 閱讀(246) 評論(0)  編輯  收藏 所屬分類: OOP


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 英山县| 溧阳市| 涞水县| 清新县| 青川县| 英德市| 大连市| 洛南县| 临泉县| 剑阁县| 灵台县| 馆陶县| 汶川县| 琼结县| 青龙| 镇宁| 桑日县| 宁远县| 武义县| 司法| 昭通市| 织金县| 团风县| 阿城市| 黄大仙区| 湘西| 定安县| 土默特左旗| 彩票| 来安县| 葵青区| 孙吴县| 射洪县| 探索| 新建县| 晴隆县| 巴中市| 阿克陶县| 新巴尔虎右旗| 房产| 昭苏县|