本例完整程序下载:
http://www.blogjava.net/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.0f, 0.0f, 0.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(500, 0.05, 0));
grades1.add(new SalaryGrade(2000, 0.1, 25));
grades1.add(new SalaryGrade(5000, 0.15, 125));
grades1.add(new SalaryGrade(20000, 0.20, 375));
grades1.add(new SalaryGrade(99999999, 0.25, 1375));
Writer writer1=new Writer(caculator,grades1);
List<SalaryGrade> grades2 = new ArrayList<SalaryGrade>();
grades2.add(new SalaryGrade(5000, 0.5, 125));
grades2.add(new SalaryGrade(99999999, 0.9, 1375));
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(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)
{

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);
}
}
}
虽然上述三段程序大小和复杂度各不一样,但它们没有优劣之分,各自都是适应环境的产物,没有一种程序结构能包打天下,但我们需要知道根据客观情况选取不同的结构,这样才能创造出优秀的程序.
以上