职责链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对明处理它为止.
职责链模式的结果如下图
.
Handler:定义一个处理请求的接口并实现后继链.
ConcreteHandler:处理负责的请求并可访问后继者.如果可处理该请求,则处理之,否则将该请求转发给后继者.
Client:向链上的具体处理者对象提交请求.
在这里先用一个简单的例子计算所得税来说明一下职责链模式在应用中的作用
先简要的说一下计算所得税的方法:
以成都为例:
计算金额----------------------应纳税额---------个税率
1、2000元/月以内免税;
2、2000元/月以上至2500元/月----不超过500元----5%
3、2500元/月以上至4000元/月----500元至2000元----10%
4、4000元/月以上至7000元/月----2000元至5000元----15%
5、7000元/月以上至22000元/月----5000元至20000元----20%
6、22000元/月以上至42000元/月----20000元至40000元----25%
7、42000元/月以上至62000元/月----40000元至60000元----30%
8、62000元/月以上至82000元/月----60000元至80000元----35%
9、82000元/月以上至102000元/月----80000元至100000元----40%
10、102000元/月以上----100000元以上----45%
(工资-2000)*相应工资范围的个税率
当你看到这样的一个计算方式之后你心里是不是已经有了自己的想法了?写一系列的if语句来一条条的判断.但这样的写法虽然可以实现目前的需求,可如果当税率发生了变化你又得拿出你的程序一步一步的修改.如果if语句的条数发生变化的话我们还必须在代码中添加必要的if判断.这对于程序的维护来说是相当麻烦的.如果我们使用职责链模式的话就可以相当简单了.
先说说我们的设计思想.
我们可以采用职责链完成所得税的计算,由职责链上的一个对象负责计算某一段的所得税.如果符合计算条件,则计算;否则由下一个对象计算.这里我们把核心的代码写出来
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CompTax
{
public class CompTax
{
private double Taxp;
private double Minincome;
private static double Disc=2000;
private CompTax NextCompTax;
public CompTax(double Minincome, double Taxp)
{
this.Minincome = Minincome;
this.Taxp = Taxp;
NextCompTax = null;
}
public double Comp(double income)
{
if(income > Minincome && (NextCompTax==null|| income< NextCompTax.Minincome))
{
return (income - Disc) * Taxp;
}
else
{
return NextCompTax.Comp(income);
}
}
public static CompTax GetInstance()
{
CompTax[] cp ={
new CompTax(2000,0.05),
new CompTax(2500,0.1),
new CompTax(4000,0.15),
new CompTax(7000,0.2),
new CompTax(22000,0.25),
new CompTax(42000,0.3),
new CompTax(62000,0.35),
new CompTax(82000,0.4),
new CompTax(102000,0.45)
};
CompTax ct=null;
for (int i = 0; i < cp.Length-1; i++)
{
if (i == 0)
ct = cp[i];
cp[i].NextCompTax = cp[i + 1];
}
return ct;
}
}
}
然后在页面上去调用.
private void button1_Click(object sender, EventArgs e)
{
textBox2.Text = CompTax.GetInstance().Comp(double.Parse(textBox1.Text)).ToString();
}
这样我们在GetInstance静态方法中把处理各种的可能连接了起来.如果第一个对象不能满足就用下一个对象来处理.一直直到能到处理为止.
在这里我们可以把cp这个数组从配置文件中读取,这样就实现了动态配置.说到这个我们还有很多地方