起因:
最近写的业务if-else判断过多,对代码的可读性和维护性都带来了很大的困难,因此想着对之前的代码重构一下。
代码类似如下:
if (){
if (){
}else if(){
}
}else if(){
if (){
}else if(){
}
}else if(){
if (){
}else if(){
}
}
解决方案:
解决方案有很多种,我这里选择的是工厂+策略模式。当然最重要的一点是,很多if else如果不是特别复杂没必要重构,不要为了用而用,这样会增加代码的维护量,适得其反。
如果不知道策略模式的可以看我之前写的文章,本文也是根据那篇文章进行进一步的扩展。
一起学之 《设计模式-策略模式》
为重构的代码如下:
//计算所交税
public class PayTaxes {
private String name;
private double money;
public PayTaxes(String name,double money){
this.money = money;
this.name = name;
}
public double calculate(){
if(name.equals("China")){
return money * 0.2;
}else if(name.equals("USA")){
return money * 0.3;
}else {
return money * 0.33;
}
}
}
//测试类
public class Test1 {
public static void main(String[] args) {
PayTaxes payTaxes = new PayTaxes("China",10000);
double taxes = payTaxes.calculate();
System.out.println("中国应交所得税为:"+taxes);
PayTaxes payTaxes2 = new PayTaxes("USA",10000);
double taxes2 = payTaxes2.calculate();
System.out.println("美国应交所得税为:"+taxes2);
PayTaxes payTaxes3 = new PayTaxes("Japan",10000);
double taxes3 = payTaxes3.calculate();
System.out.println("日本应交所得税为:"+taxes3);
}
}
我们可以看到上面的calculate() 方法中有非常复杂的if else(当然不复杂,完全没必要改变或者改成switch可能更直观。这里我们就当很复杂来处理)。下面我们先通过策略模式做一下修改。
//抽象策略
public interface PayTaxesStrategy {
double calculate(int money);
}
//具体策略中国
public class PayTaxesConcreteStrategyChina implements PayTaxesStrategy {
@Override
public double calculate( int money) {
return money * 0.2;
}
}
//具体策略美国
public class PayTaxesConcreteStrategyUsa implements PayTaxesStrategy {
@Override
public double calculate(int money) {
return money * 0.3;
}
}
//具体策略日本
public class PayTaxesConcreteStrategyJapan implements PayTaxesStrategy{
@Override
public double calculate(int money) {
return money * 0.33;
}
}
//测试类
public class Test1 {
public static void main(String[] args) {
PayTaxesStrategy payTaxes = new PayTaxesConcreteStrategyChina(10000);
double taxes = payTaxes.calculate();
System.out.println("中国应交所得税为:"+taxes);
PayTaxesStrategy payTaxes2 = new PayTaxesConcreteStrategyUsa(10000);
double taxes2 = payTaxes2.calculate();
System.out.println("美国应交所得税为:"+taxes2);
PayTaxesStrategy payTaxes3 = new PayTaxesConcreteStrategyJapan(10000);
double taxes3 = payTaxes3.calculate();
System.out.println("日本应交所得税为:"+taxes3);
}
}
如上所示我们已经通过策略模式进行了改变,但是正常的业务Text1类不能这样写应该如下:
public class Test1 {
public static void main(String[] args) {
String name = "China";
if(name.equals("China")) {
PayTaxesStrategy payTaxes = new PayTaxesConcreteStrategyChina(10000);
double taxes = payTaxes.calculate();
System.out.println("中国应交所得税为:" + taxes);
}else if(name.equals("Usa")) {
PayTaxesStrategy payTaxes2 = new PayTaxesConcreteStrategyUsa(10000);
double taxes2 = payTaxes2.calculate();
System.out.println("美国应交所得税为:" + taxes2);
}else {
PayTaxesStrategy payTaxes3 = new PayTaxesConcreteStrategyJapan(10000);
double taxes3 = payTaxes3.calculate();
System.out.println("日本应交所得税为:" + taxes3);
}
}
}
我们可以从上面发现,我们虽然解决掉了calculate() 中的if-else。但是在选择策略的时候我们又用了if-else,兜兜转转又回到了起点。所以需要增加一个工厂类来帮我们选择策略。
代码如下:
public class GetContryFactory {
private static Map<String, PayTaxesStrategy> request = new ConcurrentHashMap<String, PayTaxesStrategy>();
public static PayTaxesStrategy getByRequestType(Integer type){
return request.get(type);
}
public static void register(String name,PayTaxesStrategy spRequest){
request.put(name,spRequest);
}
}
//此时的Test1
public class Test1 {
public static void main(String[] args) {
String name = "China";
GetContryFactory.register("China",new PayTaxesConcreteStrategyChina());
GetContryFactory.register("Usa",new PayTaxesConcreteStrategyJapan());
GetContryFactory.register("Japan",new PayTaxesConcreteStrategyUsa());
PayTaxesStrategy payTaxesStrategy = GetContryFactory.getByRequestType(name);
payTaxesStrategy.calculate(10000);
}
}
我们通过一个Map去存储我们所有的策略实体类,用条件作为key,策略类作为value,要一一对应。先是在程序启动的时候认为的为我们的Map添加数据,通过调用register() 方法。然后通过工厂的getByRequestType() 方法去map中获取策略类对象(工厂代替我们生产对象)。这就是工厂+策略模式去解决if-else嵌套过多的问题。
但是我想大家应该发现了一个问题,就是我们每次都需要去手动的维护我们的Map非常麻烦,我们可以通过Spring InitializingBean 接口并重写 afterPropertiesSet 方法,将策略实现注册到工厂类 map 中。
修改策略实现类,如下只列出一个其它类似。
代码如下:
@Service
public class PayTaxesConcreteStrategyChina implements PayTaxesStrategy, InitializingBean {
@Override
public double calculate( int money) {
return money * 0.2;
}
@Override
public void afterPropertiesSet() throws Exception {
GetContryFactory.register("China",new PayTaxesConcreteStrategyChina());
}
}
至此整个项目结束,我这里还有一个contex分装类没有写,大家可以类比我之前的策略模式自行增加,工厂类返回 context,context 包住 策略实现。
git地址
启动项目输入localhost:8080即可