策略(Strategy)模式是什么?
Strategy的意思是"策略",指的是一种算法,可以整体替换算法的实现部分,能让我们轻松以不同的算法去解决同一个问题,这种模式就是Strategy模式。
策略(Startegy)模式主要登场角色:
-
Strategy(策略)
Strategy角色负责决定实现策略所必须的接口(API),可以理解为接口
-
ConcreteStrategy(具体的策略)
ConcreteStrategy角色负责实现Strategy角色的接口(API),即负责实现具体的策略,可以理解为接口的实现类
-
Context(上下文)
负责使用Strategy角色,Context角色保存了ConcreteStrategy角色的实例,并使用ConcreteStrategy角色去实现需求,可以理解为需要用到策略接口的入口类
示例案例:
提示:此案例示例图来自element-ui树形组件:
文件夹可拖拽树形组件
拖拽主要事件:
- prev —— 放置在目标节点前
- inner —— 插入至目标节点内
- next —— 放置在目标节点后
示例代码:
提示:这里只是示例代码,并不是真实实现
文件夹实体Folder
public class Folder {
private Long id;
private String name;
private Long parentId;
private String path;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
拖拽类型枚举(FolderDragTypeEnum )
public enum FolderDragTypeEnum {
PREV("folderPrevDragStrategy"),
INNER("folderInnerDragStrategy"),
NEXT("folderNextDragStrategy"),
;
private final String serviceName;
FolderDragTypeEnum(String serviceName) {
this.serviceName = serviceName;
}
public String getServiceName() {
return serviceName;
}
}
拖拽策略接口(FolderDragStrategy)
public interface FolderDragStrategy {
/**
* 拖拽方法
*
* @param originNode(操作的源文件夹)
* @param targetNode(操作的目标文件夹)
*/
void drag(Folder originNode, Folder targetNode);
}
文件夹向前拖拽策略实现FolderPrevDragStrategyImpl
@Service("folderPrevDragStrategy")
public class FolderPrevDragStrategyImpl implements FolderDragStrategy {
@Override
public void drag(Folder originNode, Folder targetNode) {
System.out.println("拖拽源文件夹 到 目标文件夹前面开始...");
//TODO
System.out.println("拖拽源文件夹 到 目标文件夹前面结束...");
}
}
文件夹拖到里面策略实现FolderInnerDragStrategyImpl
@Service("folderInnerDragStrategy")
public class FolderInnerDragStrategyImpl implements FolderDragStrategy {
@Override
public void drag(Folder originNode, Folder targetNode) {
System.out.println("拖拽源文件夹 到 目标文件夹里面开始...");
//TODO
System.out.println("拖拽源文件夹 到 目标文件夹里面结束...");
}
文件夹向后拖拽策略实现(FolderNextDragStrategyImpl )
@Service("folderNextDragStrategy")
public class FolderNextDragStrategyImpl implements FolderDragStrategy {
@Override
public void drag(Folder originNode, Folder targetNode) {
System.out.println("拖拽源文件夹 到 目标文件夹后面开始...");
//TODO
System.out.println("拖拽源文件夹 到 目标文件夹后面结束...");
}
}
需要用到拖拽策略的上下文context
这里是我的对外提供的接口FoldDragServiceImpl
@RestController("fold")
public class FoldDragServiceImpl {
//spring会将实现同一策略接口的所有策略实现类放到map
@Autowired
private Map<String , FolderDragStrategy> folderDragStrategyMap;
@Autowired
private FolderMapper folderMapper;
@PutMapping("drag")
public void dragFolder(@RequestBody FolderDragCommand command){
Folder originFolder = folderMapper.getById(command.getOriginId());
Folder targetFolder = folderMapper.getById(command.getTargetId());
FolderDragStrategy folderDragStrategy = folderDragStrategyMap.get(command.getDragType().toString());
folderDragStrategy.drag(originFolder , targetFolder);
}
}
总结
策略模式非常实用,可以替换很多if else,比如上面代码如果要用if else 实现那么可能要写3个判断执行对应方法
使用策略模式可以提高代码可读性,方便后面随着业务扩展,代码不断调整
@RestController("fold")
public class FoldDragServiceImpl {
//spring会将实现同一策略接口的所有策略实现类放到map
@Autowired
private Map<String, FolderDragStrategy> folderDragStrategyMap;
@Autowired
private FolderMapper folderMapper;
@PutMapping("drag")
public void dragFolder(@RequestBody FolderDragCommand command) {
if (FolderDragTypeEnum.PREV == command.getDragType()) {
new FolderPrevDragStrategyImpl().drag(originFolder, targetFolder);
} else if (FolderDragTypeEnum.INNER == command.getDragType()) {
new FolderInnerDragStrategyImpl().drag(originFolder, targetFolder);
} else if (FolderDragTypeEnum.NEXT == command.getDragType()) {
new FolderNextDragStrategyImpl().drag(originFolder, targetFolder);
}
}
}