和風(fēng)細雨

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

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

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

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

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

          級 數(shù) 全月應(yīng)納稅所得額 稅率(%)  稅率      速算扣除數(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)結(jié)束,我們可以使用傳統(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)結(jié)束前是有可能變化的,或者說變化不可預(yù)期,用戶一定程序上也希望自己修改,IF分支的結(jié)構(gòu)將不再適用,但程序可以停止,這時就應(yīng)該把分支語句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(
          "設(shè)定鎖為讀取狀態(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(
          "設(shè)定鎖為寫入狀態(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);
                  }

              }

          }

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

          以上

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


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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 井冈山市| 海门市| 五常市| 南川市| 古蔺县| 惠东县| 大同市| 桂林市| 巴楚县| 额济纳旗| 烟台市| 绥宁县| 黄龙县| 民勤县| 米脂县| 中卫市| 建平县| 高清| 油尖旺区| 苗栗市| 天气| 晴隆县| 鹤山市| 湖北省| 确山县| 育儿| 宜君县| 昭觉县| 卓资县| 兴仁县| 文水县| 通道| 浦东新区| 平安县| 邳州市| 通许县| 贡山| 内丘县| 长岭县| 鸡西市| 五峰|