策略模式定义
将一组算法封装到实现共同接口的独立类中,使得它们可以相互替换。
策略举例
项目中执行需求:有关类型1的需求,由A做;类型2的需求,由B做;类型3的需求,由C做。
代码实现
public void doItem(int type) {
if (type == 1) {
// do action
workA();
System.out.println("A do work.");
} else if (type == 2) {
// do action
workB();
System.out.println("B do work.");
} else if (type == 3) {
// do action
System.out.println("C do work.");
} else {
// do action
workC();
System.out.println("do it yourself.");
}
}
我们最快想到的,就是if…else…或者case。大多数情况下,这样是合理的。
但是,如果type越来越多,action越来越复杂,doItem方法就会变得越来越庞大,代码的可读性也就会越来越差。
下面,介绍一下前段时间在项目中的一次重构经历,主要用到策略模式。
策略模式简单示例
// 定义策略接口
public interface Strategy {
public void work();
}
// 策略A
public class StrategyA implements Strategy {
@Override
public void work() {
System.out.println("A do work.");
}
}
// 策略B
public class strategyB implements Strategy {
@Override
public void work() {
System.out.println("B do work.");
}
}
// 策略C
public class strategyC implements Strategy {
@Override
public void work() {
System.out.println("C do work.");
}
}
// 环境类
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void work() {
this.strategy.work();
}
}
public void doItem() {
Context ct = new Context(new StrategyA());
ct.work();
ct.setStrategy(new StrategyB());
ct.work();
}
项目重构实战
原部分代码
public void pushData2Sap(String type, List<Long> ids) {
Object[] dtos = null;
if (type.equals("customer")) {
List<CustomerDTO> dtoList = customerService.query(ids);
dtos = new Object[dtoList.size()];
dtos = dtoList.toArray();
} else if (type.equals("product")) {
List<ProductDTO> dtoList = new ArrayList<ProductDTO>();
for (Long id : ids) {
ProductDTO d = productService.queryById(id);
dtoList.add(d);
}
dtos = new Object[dtoList.size()];
dtos = dtoList.toArray();
} else if (type.equals("provider")) {
List<ProviderDTO> dtoList = providerService.query(ids);
dtos = new Object[dtoList.size()];
dtos = dtoList.toArray();
} else if (type.equals("contact")) {
List<ContactDTO> dtoList = contactService.query(ids);
dtos = new Object[dtoList.size()];
dtos = dtoList.toArray();
}
RedisHelper.push(dtos);
}
Spring + 工厂 + 策略模式重构后
// applicationContext-bean.xml
<!-- 推送sap策略工厂 -->
<bean id="contextSpringFactory" class="core.util.ContextSpringFactory">
<property name="stgMap">
<map>
<entry key="customer" value-ref="customerServiceImpl"/>
<entry key="product" value-ref="productServiceImpl"/>
<entry key="provider" value-ref="providerServiceImpl"/>
<entry key="contact" value-ref="contactServiceImpl"/>
</map>
</property>
</bean>
// 策略工厂
@Component
public class ContextSpringFactory {
private Map<String, IPushSapStrategy<?>> stgMap = new HashMap<String, IPushSapStrategy<?>>();
public Map<String, IPushSapStrategy<?>> getStgMap() {
return stgMap;
}
public void setStgMap(Map<String, IPushSapStrategy<?>> stgMap) {
this.stgMap = stgMap;
}
public List<?> doAction(String strType, List<Long> ids) {
return this.stgMap.get(strType).querySapObjs(ids);
}
}
// RedisHelper
// 引入策略工厂
@Resource
private ContextSpringFactory contectSpringFactory;
public void pushData2Sap(String type, List<Long> ids) {
List<?> sapDtos = contectSpringFactory.doAction(typeId, ids);
Object[] dtos = dtoList.toArray();
RedisHelper.push(dtos);
}
这样,利用Spring+工厂模式+策略模式完成了代码重构