代码执行逻辑(伪代码),实际项目更复杂
public int getDistance(int parkId, int count) {
// 如果是公园x,1个间距为y(比如:10)米
if (parkId == 1) {
return 10 * count;
} else if (parkId == 2) {
return 5 * count;
} else if (parkId == 3) {
return 50 * count;
} else {
// 默认 20米
return 20 * count;
}
}
- 代码重构定义抽象方法
public abstract class AbstractParkStrategy {
/**
* 计算距离抽象方法
* @param count
* @return
*/
public abstract int calcDistance(int count);
}
- 具体实现类
public class PeopleParkStrategy extends AbstractParkStrategy {
Logger log = LoggerFactory.getLogger(PeopleParkStrategy.class);
@Override
public int calcDistance(int count) {
log.info("人民公园距离计算");
return 10 * count;
}
}
public class BeiHaiParkStrategy extends AbstractParkStrategy {
Logger logger = LoggerFactory.getLogger(BeiHaiParkStrategy.class);
@Override
public int calcDistance(int count) {
logger.info("北海公园计算距离");
return 100 * count;
}
}
- 实现一个持有抽象类AbstractParkStrategy的DistanceContext类
/**
* 环境角色类
**/
public class DistanceContext {
/**
* 持有策略抽象类
*/
private AbstractParkStrategy abstractParkStrategy;
// 通过构造方法注入,也可以通过其他方式注入
public DistanceContext(AbstractParkStrategy parkStrategy) {
this.abstractParkStrategy = parkStrategy;
}
public int calcDistance(int count) {
return abstractParkStrategy.calcDistance(count);
}
}
- 测试
@Test
public void testStrategy() {
DistanceContext distanceContext = new DistanceContext(new PeopleParkStrategy());
int distance = distanceContext.calcDistance(2);
log.info("获得距离:{}", distance);
}
从示例可以看出,策略模式仅仅封装算法,并不决定在何时使用何种算法。而且,在什么时候使用什么算法也是由客户端决定的。
- springboot策略模式
主要利用Spring的@Autowired注解来将实例化的策略实现类注入到一个Map当中,然后通过key获取到服务。使用concurrentHashMap是防止多线程操作的时候出现问题。
@Service("peopleParkStrategy")
public class PeopleParkStrategy extends AbstractParkStrategy {
// ...
}
改进DistanceSpringContext类
@Component("distanceSpringContext")
public class DistanceSpringContext {
@Autowired
private final Map<String, AbstractParkStrategy> strategyMap = new ConcurrentHashMap<>(3);
private AbstractParkStrategy strategy;
public void factory(String serviceName) {
strategy = strategyMap.get(serviceName);
}
public int calcDistance(int count) {
return strategy.calcDistance(count);
}
}
@Component注解将DistanceSpringContext的实例化也交由Spring来管理了。而@Autowired注解会将容器中AbstractParkStrategy的实现类(注解了@Service)注入到该Map中。其中key就是@Service中指定的实例化服务的名称,value值便是对应的对象。
- 测试
@Resource
private DistanceSpringContext distanceSpringContext;
@org.junit.Test
public void testDistanceContext(){
distanceSpringContext.factory("beiHaiParkStrategy");
int distance = distanceSpringContext.calcDistance(10);
log.info("dist:{}",distance);
}
使用枚举类完善代码
public enum ParkEnum {
DEFAULT_PARK(0,"peopleParkStrategy","人民公园"),
PEOPLE_PARK(1,"peopleParkStrategy","人民公园"),
BEIHAI_PARK(2,"beiHaiParkStrategy","北海公园");
ParkEnum(int code,String serviceName,String des){
this.code = code;
this.serviceName = serviceName;
this.des = des;
}
public static ParkEnum valueOf(int code){
for (ParkEnum parkEnum: ParkEnum.values()) {
if(parkEnum.getCode()==code){
return parkEnum;
}
}
return DEFAULT_PARK;
}
private int code;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
private String serviceName;
private String des;
}
- 改进DistanceSpringContext类,获取对象服务通过枚举类
@Component("distanceSpringContext")
public class DistanceSpringContext {
@Autowired
private final Map<String,AbstractParkStrategy> strategyMap = new ConcurrentHashMap<>(3);
public AbstractParkStrategy getService(int code){
ParkEnum parkEnum = ParkEnum.valueOf(code);
return strategyMap.get(parkEnum.getServiceName());
}
}
- 测试
@Resource
private DistanceSpringContext distanceSpringContext;
@org.junit.Test
public void testDistanceContext(){
AbstractParkStrategy parkStrategy = distanceSpringContext.getService(ParkEnum.PEOPLE_PARK.getCode());
int distance = parkStrategy.calcDistance(10);
log.info("distance:{}",distance);
}
总结
只是单纯理论学习策略模式,是很难运用的好。只有结合实践场景,根据需要进行改进。这里结合了SpringBoot的特性,使用策略模式提高代码的可读性,易维护。