策略模式:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化
策略模式在我们的应用场景中,主要应用在两个场景:
场景一:日志存储的问题,一般我们的日志信息都会存放在了elk或者mysql中,但是我们不能保证我们的elk和mysql一直没出现问题,那么问题来了,如果我们的持久化崩溃不可用了咋办,别着急,我们需要有备用的持久化方案,简单的方法就是切换到了文件,以文件的形式进行持久化,然后数据库恢复之后进行定时的将文件持久化到数据库中,保证了日志的不丢失;而如果数据库恢复正常了又可以直接持久化到数据库中,不用繁琐的进行人工的操作
场景二:我们在写代码的时候,难免会出现很多的if和else的问题,如果我们想优化代码,使用更优雅一点,那么也可以使用策略模式来进行,根据不同的策略调用不同的方法,实现不同的效果。
对了,我先介绍一下策略模式要记住的三个单词:
(1)Strateg:策略,需要定义一个策略接口,用于实现每个策略的具体的内容,每个策略的内容需要实现这个接口和方法
(2)Context:上下文,用于处理使用哪一种策略
(3)Controller:控制层调用了哈哈哈
下面进行场景一的代码示范,直接复制就可以运行了哈:
场景一:
(1)定义一个日志策略接口
public interface LogStrategy {
/**
* 记录日志
* @param msg 需记录的日志信息
*/
public String log(String msg);
}
(2)我们有两种方法持久化,正常入库流程,非正常文件持久化流程;所以我们定义两个类实现LogStrategy接口
(2.1)定义数据库类并实现LogStrategy
public class DbLog implements LogStrategy{
@Override
public String log(String msg) {
System.out.println("现在把 '"+msg+"' 记录到数据库中");
return "数据库";
}
}
(2.2)定义文件类并实现LogStrategy
/**
* 把日志记录到文件
*/
public class FileLog implements LogStrategy{
@Override
public String log(String msg) {
System.out.println("现在把 '"+msg+"' 记录到文件中");
return "文件";
}
}
(三).好了,我们现在来进行第三步了,定义上下文类
public class LogContext {
public String log(String msg){
LogStrategy logStrategy=new DbLog();
String falge="";
try{
//正常的时候会走 数据入库的操作;出现异常之后就会使用文件下发的模式进行文件的下发进行持久化操作,保证日志的完整
falge= logStrategy.log(msg);
}catch (Exception e){
logStrategy=new FileLog();
falge= logStrategy.log(msg);
}
return falge;
}
}
注意:这里我们使用的是try和catch;为什么这样操作呢?因为这样日志默认进来的时候就进行数据库的入库流程;只有数据库异常了之后,就会执行catch方法,就会执行文件持久化方式,这样就保证了日志不丢失的问题,还有一个好处是数据库恢复了之后,日志又继续进行了数据库的入库的流程,保障了系统的可用。
(四)控制层调用
@Controller
@RequestMapping("log")
public class LogController {
@ResponseBody
@RequestMapping("test")
public String logtest(@Param("msg")String msg){
LogContext logContext=new LogContext();
return logContext.log(msg);
}
}
场景二
应用场景:减少方法中的if和else;我们在使用转发功能的时候,会转发到不同的应用,假设我们目前的需求是需要转发到新浪和微信;但是后续接入应用中心一多起来,我们就可能转发到更多的应用中心了,如果是这样的话,按照我们之前的常规的方法就是在同一个方法里面增加if和else来进行判断,这样的话少量的if还好,如果是很多的if的话,那么就很容易产生bug;这时候我们就可以使用策略模式来进行改造
上代码:
(1)定义个转发策略接口DealStrategy
public interface DealStrategy{
String dealMythod(String option);
}
(2)新浪和微信实现这个接口和方法进行不同策略的处理
public class DealSina implements DealStrategy{
@Override
public String dealMythod(String option) {
return "DealSina";
}
}
public class DealWeChat implements DealStrategy{
@Override
public String dealMythod(String option) {
return "DealWeChat";
}
}
(3)定义上下文,进行策略的归属
import java.util.ArrayList;
import java.util.List;
public class StrategyContext {
//静态代码块,先加载所有的策略
protected static List<DealContext> algs = new ArrayList();
static {
algs.add(new StrategyContext.DealContext("Sina",new DealSina()));
algs.add(new StrategyContext.DealContext("WeChat",new DealWeChat()));
}
public static class DealContext {
private String type;
private DealStrategy deal;
public DealContext(String type,DealStrategy deal){
this.type = type;
this.deal = deal;
}
public DealStrategy getDeal(){
return deal;
}
public boolean options(String type){
return this.type.equals(type);
}
}
}
(4)进行控制层的调用了
import static com.example.csv.StrategyUtil.StrategyContext.algs;
@RestController
@RequestMapping("strategy")
public class StrategyController {
@ResponseBody
@RequestMapping("Sina")
public String shareOptions(String type){
DealStrategy dealStrategy = null;
for (StrategyContext.DealContext deal : algs) {
if (deal.options(type)) {
dealStrategy = deal.getDeal();
break;
}
}
return dealStrategy.dealMythod(type);
}
}
这样,就可以完成调用了;如果需要信增加策略的话,只需要新定义一个类并实现公共接口的方法,然后在static代码块中添加对应的即可
好了,策略模式完成了,代码直接复制即可!
缺点:就是有点费类哈哈哈