减少if-else的使用——策略模式


代码是死的,人是活的。具体怎么使用还得看具体的场景。这里只是抛砖引玉。

策略模式

策略模式,不用多说,直接代码:

  1. 定义一个策略接口:
public interface Strategy {
    
    

    /**
     * 具体的策略,做某个事情
     * 
     * @author FYK
     */
    void doSomething();
}
  1. 具体的策略类:
public class StrategyA implements Strategy {
    
    

    @Override
    public void doSomething() {
    
    
        System.out.println("策略A    AAAAAAAAAAAAA");
    }
}

public class StrategyB implements Strategy {
    
    

    @Override
    public void doSomething() {
    
    
        System.out.println("策略B    BBBBBBBBB");
    }
}

public class StrategyC implements Strategy {
    
    

    @Override
    public void doSomething() {
    
    
        System.out.println("策略C     CCCCCCCCC");
    }
}
  1. 策略上下文调用策略:
public class StrategyContext {
    
    

    @Setter
    private Strategy strategy;

    /**
     * 执行策略
     *
     * @author FYK
     */
    public void doStrategy() {
    
    
        strategy.doSomething();
    }

}

使用策略模式

完成以上代码之后,策略模式算是完成了。当初也就是学到这里,代码完全明白,但是用的时候懵逼,这里给出一个大多数使用策略模式的方式:

public class StrategyContextTest {
    
    

    @org.junit.Test
    public void doStrategy() {
    
    
        StrategyContext context = new StrategyContext();
        // 使用策略A
        context.setStrategy(new StrategyA());
        context.doStrategy();
        // 使用策略B
        context.setStrategy(new StrategyB());
        context.doStrategy();
        // 使用策略C
        context.setStrategy(new StrategyC());
        context.doStrategy();
    }
}

问题

以上,使用策略模式中,有一个问题:当要使用策略A的时候,是具体的传入了一个StrategyA的实例。这个在实际使用的时候,很难做到(这要求使用者清楚每个策略的实现类是做什么的,以及如何构造实例类)。更主要的是:通常情况下有很多策略类,具体需要哪个策略类,是需要一个参数来判断的。所以,常见的代码是配合工厂模式,通过一个标识符来判断该创建那个策略类:

if(flag = A){
    
    
	return A;
}else if(flag = B){
    
    
	return B
}else if(flag = C){
    
    
	return C
}

因此,每增加一个策略类,就需要修改这个工厂方法中的if else代码。if else代码多了之后,照成的问题,懂的人都懂,以下介绍解决这些if esle的一些方法。

减少if else:枚举法

枚举中,可以定义一个方法。
如下:将所有的策略都定义在一个枚举类中(是情况而定)

public enum StrategyEnum {
    
    

    StrategyA {
    
    
        @Override
        void doSomething() {
    
    
            System.out.println("策略A    AAAAAAAAAAAAA");
        }
    },

    StrategyB {
    
    
        @Override
        void doSomething() {
    
    
            System.out.println("策略B    BBBBBBBBBBBBB");
        }
    },

    StrategyC {
    
    
        @Override
        void doSomething() {
    
    
            System.out.println("策略C    CCCCCCCCCCCCC");
        }
    };

    abstract void doSomething();
}

然后策略上下文:

@UtilityClass
public class StrategyContext {
    
    

    public void deStrategyEnum(String strategyFlag){
    
    
        StrategyEnum strategyEnum = StrategyEnum.valueOf(strategyFlag);
        strategyEnum.doSomething();
    }

}

这样,只需要传入在枚举中定义的策略类的名字就可以了:

public class StrategyContextTest {
    
    

    @Test
    public void deStrategyEnum() {
    
    
        StrategyContext.deStrategyEnum("StrategyA");
    }
}

通常而言,策略标识,是由调用方(例如前端或者配置文件)传入的,这样,如果需要增加某个策略,就只需要在策略枚举中加入策略实现即可,无需其他操作了。

减少if else:享元模式

享元模式来实现这个减少if else很简单:这里说下原理,代码就不全写了。
享元模式的基本格式:

public class StrategyFactory {
    
    
	private Map<String, Strategy> strategyManager = new ConcurrentHashMap<>();
	
	public Strategy getStrategy(String strategyFlag){
    
    
		//一般而言,策略Strategy 实现类,都是放在一个包下的(或者是有一定的规律的地方,这样也便于以后查找所有的策略类代码),既然是放在一个包下,那么就可以通过一个扫描工具类,加载出所有的策略类实现。
		Strategy strategy = strategyManager.get(strategyFlag);
		if(strategy== null){
    
    
			//扫描策略类,放入map中
			strategyManager .put(strategyFlag, strategy);
		}
		return strategy;
	}
}

所以,简单的说,就是利用享元模式,将所有的策略以key-value的形式放入一个map中,然后在使用的时候,通过key,在map中使用get方法就可以获得具体的策略了,这样也减少了if else的使用。

总结

以上方式,是我目前了解到了可以减少if else的使用方法,这里只是用策略模式来举例,并不是单单只能再这里使用,后续有发现更好的方式再继续更新。
另外,这些个方法各有各的好处,具体的是使用还得看个人。顺便说下:并不是出现多个if else的地方就需要优化,要看具体的业务场景,有时候多个if else代码或许会让代码更加清晰。

猜你喜欢

转载自blog.csdn.net/fyk844645164/article/details/113481193