手写模拟Thread与Runnable的策略模式

本文通过一个计算个人所得税的例子,展示了如何运用策略模式来处理税率变化的需求,避免了直接修改代码。类比Java中的Thread和Runnable接口,强调了将业务逻辑与执行单元分离可以提高代码的灵活性。通过创建不同的策略类,可以方便地应对税率计算规则的变化,这与多线程中提交任务给线程执行的理念相似。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

假设我们现在需要计算一个员工的个人所得税,于是我们写了如下工具类,传入基本工资和奖金即可调用calculate得出应纳税额。

税率计算类,模拟的是Thread类。

/**
 * 税率计算类。模拟Thread类的“模板方法模式”
 */
public class TaxCalculator {
    //工资
    private final double salary;
    //奖金
    private final double bonus;

    //构造器
    public TaxCalculator(double salary, double bonus) {
        this.salary = salary;
        this.bonus = bonus;
    }

    /**
     * 计算税率的业务逻辑。
     * 供子类重写。相当于Thread的run方法
     */
    protected double calcTax() {
        return 0.0d;
    }

    /**
     * 执行税率计算。
     * 供外部调用。相当于Thread的start方法
     * @return
     */
    public double calculate() {
        return this.calcTax();
    }

    public double getSalary() {
        return salary;
    }

    public double getBonus() {
        return bonus;
    }
}

测试一下:

public class TaxCalculatorMain {
    public static void main(String[] args) {
        TaxCalculator taxCalaculator = new TaxCalculator(10000d, 2000d) {
            @Override
            //重写计算税率方法,实现自己的业务逻辑
            protected double calcTax() {
                return getSalary() * 0.1 + getBonus() * 0.15;
            }
        };
        double calcute = taxCalaculator.calculate();
        System.out.println(calcute);
    }
}

这样写有什么问题?我们将应纳税额的计算写死了:salary * 0.1 + bonus * 0.15,而税率并非一成不变的,客户提出需求变动也是常有的事!难道每次需求变更我们都要手动更改这部分代码吗?

这时策略模式来帮忙:当我们的需求的输入是不变的,但输出需要根据不同的策略做出相应的调整时,我们可以将这部分的逻辑抽取成一个接口:

public interface CalculatorStrategy {
    double calculate(double salary,double bonus);
}

具体策略实现: 

public class SimpleCalculatorStrategy implements CalculatorStrategy {
    private final static double SALARY_RATE = 0.1;
    private final static double BOUNS_RATE = 0.15;

    @Override
    public double calculate(double salary, double bonus) {
        return salary * SALARY_RATE + bonus * BOUNS_RATE;
    }
}

上面的税率计算类调整一下,业务代码仅调用接口:

/**
 * 税率计算器。模拟Thread类的“模板方法模式”
 */
public class TaxCalculator {
    //工资
    private final double salary;
    //奖金
    private final double bonus;

    //定义抽象出来计算税率的接口
    private CalculatorStrategy calculatorStrategy;

    //构造器
    public TaxCalculator(double salary, double bonus) {
        this.salary = salary;
        this.bonus = bonus;
    }

    /**
     * 相当于Thread的run方法
     * 计算税率的业务逻辑放到策略类里面,不需要再重写了
     * 
     */
    protected double calcTax() {
        return calculatorStrategy.calculate(salary, bonus);
    }

    /**
     * 相当于Thread的start方法
     * 执行税率计算。供外部调用。
     * @return
     */
    public double calculate() {
        return this.calcTax();
    }

    public void setCalculatorStrategy(CalculatorStrategy calculatorStrategy) {
        this.calculatorStrategy = calculatorStrategy;
    }
}

测试一下:

public class TaxCalculatorMain {
    public static void main(String[] args) {
        // 只负责执行税率计算任务。类似于Thread
        TaxCalaculator taxCalaculator = new TaxCalaculator(10000d, 2000d);
        // 负责具体税率任务逻辑。类似于Runnable
        CalculatorStrategy calculatorStrategy = new SimpleCalculatorStrategy();
        taxCalaculator.setCalculatorStrategy(calculatorStrategy);
//        taxCalaculator.setCalculatorStrategy(((salary, bonus) -> salary * 0.1 + bonus * 0.15));

        System.out.println(taxCalaculator.calculate());
    }
}

假如,税率计算规则变成了(salary + bonus) * 1.5,我们只需新增一个策略类:

public class AnotherTaxCalculatorStrategy implements CalculatorStrategy {
    @Override
    public double calculate(double salary, double bonus) {
        return (salary + bonus) * 1.5;
    }
}

这与Thread中的逻辑执行单元run抽取成一个接口Runnable有着异曲同工之妙。因为实际业务中,需要提交给线程执行的任务我们是无法预料的,抽取成一个接口之后就给我们的应用程序带来了很大的灵活性。

Thread的职责就是执行任务,而将业务逻辑单独抽取出来作为一个逻辑执行单元,当需要执行时提交给线程即可。于是就有了Runnable接口。



 

参考:

《汪文君 JAVA 多线程编程实战》

https://www.jianshu.com/p/1f491f814c27

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值