定义
策略模式属于对象的行为模式,针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以互相替换。根据不同情况,将算法分割开来,委派给不同的对象,即一系列的具体策略类,在其上层还有一个共同的抽象策略类。
如下为策略模式的通用类图:
Context:上下文角色,负责引用需要的Strategy。 (策略执行者)
Strategy:抽象策略角色。一般为接口或抽象类,用来提取策略的共同行为,具体策略实现类需实现其接口。
ConcreteStrategy:具体策略角色。实现或继承抽象策略角色,针对不同的情况进行逻辑处理。
策略模式的简单实现
// 上下文角色(环境)
public class Context{
private final Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public void go(){
strategy.go();
}
}
// 抽象策略角色
public interface Strategy{
void go();
}
// 具体策略角色A
public class ConcreteStrategyA implements Strategy{
@Override
public void go() {
System.out.println("go A");
}
}
// 具体策略角色B
public class ConcreteStrategyB implements Strategy{
@Override
public void go() {
System.out.println("go B");
}
}
使用:
public static void main(String[] args) throws IOException {
Strategy strategy = new ConcreteStrategyA();
Context context = new Context(strategy);
context.go();
}
策略模式的使用场景及案例
策略模式可以根据不同处理逻辑来生成各种不同的具体策略类,而if else也是通过判断各种不同情况来进行不同的逻辑处理。所以,策略模式肯定是对比ifelse更好的处理方式。
通知很常见吧,常见的聊天软件,还是各种游戏都有各种各样的通知,比如你是一个博主,有人点赞了你的博文,那系统要发送一个有人点赞的通知,有人收藏了你的博客,系统要发送一个有人收藏你的博客的通知,有人评论了你的博客,系统要发送...,这种通知就很多了。按照一般情况下的实现方式:
if(点赞){
// 发送点赞通知
}else if(收藏){
// 发送收藏通知
}else if(评论){
// 发送评论通知
}else if(..){
....
}
这种方式不说代码美不美观吧,拓展也是及其不方便,增加一个通知则需要对原有实现类进行修改,和开闭原则不相符。对这些通知处理的管理也及其不方便。
这时候策略模式就派上了用场,那如何用策略模式进行修改呢?
首先要定义一个抽象接口,无论是什么通知,共同行为都是发送通知,所以:
public interface INotifyStrategy{
/**
* 发送通知
*/
void sendNotify();
/**
* 获取类型
*/
String getType();
}
定义好抽象接口后,就需要根据不同的处理逻辑来生成不同的具体实现类,这里就拿点赞和收藏两种情况举例。
/**
* 点赞通知具体实现
*/
public class LikedNotifyStrategy implements INotifyStrategy{
@Override
public void sendNotify() {
System.out.println("发送点赞通知");
}
@Override
public String getType() {
return "liked";
}
}
/**
* 收藏通知具体实现
*/
public class CollectedNotifyStrategy implements INotifyStrategy{
@Override
public void sendNotify() {
System.out.println("发送收藏通知");
}
@Override
public String getType() {
return "collected";
}
}
/**
* 通知上下文角色
*/
class NotifyContext{
private final INotifyStrategy notifyStrategy;
public NotifyContext(INotifyStrategy notifyStrategy){
this.notifyStrategy = notifyStrategy;
}
public void sendNotify(){
notifyStrategy.sendNotify();
}
}
如果按照之前的方式,则还是无法避免通过对if else的判断,选择具体实现类。这里可以结合工厂模式,引入一个策略工厂,可以根据不同的类型自动选择相应的具体实现类。
@Component
public class NotifyStrategyFactory implements ApplicationContextAware {
private static Map<String,INotifyStrategy> strategyMap;
/**
* 通过上下文获取容器中注册的INotifyStrategy类,并将其放入map中。
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, NotifyStrategy> map = applicationContext.getBeansOfType(INotifyStrategy.class);
strategyMap = new HashMap<String, INotifyStrategy>();
map.forEach((key, value) -> strategyMap.put(value.getType(), value));
}
private NotifyStrategyFactory(){}
public static NotifyStrategy getInstance(String type){
return strategyMap.get(type);
}
}
进行使用
public static void main(String[] args) {
String type = "liked";
NotifyContext notifyContext = new NotifyContext(NotifyStrategyFactory.getInstance(type));
notifyContext.sendNotify();
}
相较于之前if else的写法,是不是好看了很多?
优缺点
优点:
- 策略模式符合开闭原则
- 避免使用大量的if else等条件判断语句
- 易于拓展
缺点:
- 必须先行知道所有的策略类,需自行选择使用哪个策略类。
- 会多出大量的策略类,加大维护成本和难度。