和風細雨

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

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

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

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

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

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


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


          1.過程式方法:
          如果說需求(稅率和扣除數)在較長一段時間內不會變化,也就是說需求變化時,程序生命已經結束,我們可以使用傳統的分支語句來編碼,程序寫出來極簡單.

          package com.sitinspring.processstyle;

          /**
           * Main函數所在的類
           * 
          @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));
                  }
                  
              }

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

          Main類:
          package com.sitinspring.oostyle;

          /**
           * Main函數所在的類
           * 
          @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方法
          如果說需求(稅率和扣除數)是人為動態指定的,且整個系統是7*24小時的系統,一般不允許停機.這樣的情況下要求程序具有熱插拔的能力,這時,我們必須加上一個讀寫鎖才能解決問題.

          Main類:
          package com.sitinspring.dynamicoostyle;

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

          import com.sitinspring.oostyle.SalaryGrade;

          /**
           * Main函數所在的類
           * 
           * 
          @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{
              
          // 讀狀態
              private boolean isRead;
              
              
          // 寫狀態
              private boolean isWrite;
              
              
          public synchronized void readLock(){
                  
          // 有寫入時讀取線程停止
                  while(isWrite){
                      
          try{    
                          System.out.println(
          "有線程在進行寫入,讀取線程停止,進入等待狀態");
                          wait();
                      }

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

                  }

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

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

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

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

                  }

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

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

                  }

                  
                  System.out.println(
          "設定鎖為寫入狀態");
                  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);
                  }

              }

          }

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

          以上

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

          主站蜘蛛池模板: 波密县| 永济市| 亚东县| 罗源县| 六盘水市| 邓州市| 抚顺市| 保康县| 榆树市| 枞阳县| 洪湖市| 新丰县| 黄冈市| 安宁市| 威远县| 资中县| 邻水| 开封市| 海淀区| 洪洞县| 铁岭市| 滦南县| 泸定县| 葫芦岛市| 林周县| 永新县| 边坝县| 寿光市| 安塞县| 光山县| 石河子市| 巫山县| 杭州市| 揭东县| 和田县| 徐水县| 阿荣旗| 海淀区| 河津市| 宁晋县| 砀山县|