策略模式 1. 策略模式要解决什么问题? 当你的系统有一类业务,输入不同,处理规则不同,但是处理结果一致,策略模式就适合你。
比如,消息通知
type=email:走 SMTP
type=sms:走短信网关
type=webhook:发 HTTP
type=ding:钉钉机器人
这个规则可能会不断追加,调整,最简单的方式就是写if-else
1 2 3 4 5 6 7 8 9 10 11 public void notify (String type, String target, String content) { if ("email" .equals(type)) { } else if ("sms" .equals(type)) { } else if ("webhook" .equals(type)) { } else { throw new IllegalArgumentException ("unknown type" ); } }
分支会越写越长、越来越难改、测试也难拆。
而策略模式就是为了解决这个问题而存在的。
2. 策略模式怎么实现? 策略模式,就是把算法封装起来,让调用者选择使用哪个算法。
2.1 策略模式有以下几个组成元素:
策略接口:定义了算法的抽象,通常由抽象类或抽象方法组成。
策略实现类:实现了策略接口,定义了具体的算法。
上下文:持有策略接口的引用,调用者通过上下文调用策略接口,从而调用具体的算法。
策略工厂:创建策略实现类,并返回给调用者。
2.2 策略模式实现代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 [import java.util.Map;public record NotifyRequest ( String target, String content, Map<String, Object> extras ) {}public record NotifyResult ( boolean success, String message ) { public static NotifyResult ok (String msg) { return new NotifyResult (true , msg); } public static NotifyResult fail (String msg) { return new NotifyResult (false , msg); } }public interface NotifyStrategy { String type () ; NotifyResult send (NotifyRequest req) ; } [public class NotifyStrategyRegistry { private final Map<String, NotifyStrategy> map; public NotifyStrategyRegistry (List<NotifyStrategy> strategies) { this .map = strategies.stream() .collect(Collectors.toUnmodifiableMap( NotifyStrategy::type, Function.identity(), (a, b) -> { throw new IllegalStateException ("Duplicate type: " + a.type()); } )); } public NotifyStrategy get (String type) { NotifyStrategy s = map.get(type); if (s == null ) throw new IllegalArgumentException ("Unknown type: " + type); return s; } } [public class EmailNotifyStrategy implements NotifyStrategy { @Override public String type () { return "email" ; } @Override public NotifyResult send (NotifyRequest req) { if (!req.target().contains("@" )) { return NotifyResult.fail("invalid email: " + req.target()); } System.out.println("[EMAIL] to=" + req.target() + " content=" + req.content()); return NotifyResult.ok("email sent" ); } } [public class NotifyService { private final NotifyStrategyRegistry registry; public NotifyService (NotifyStrategyRegistry registry) { this .registry = registry; } public NotifyResult notify (String type, NotifyRequest req) { if (req == null ) return NotifyResult.fail("request is null" ); if (req.target() == null || req.target().isBlank()) return NotifyResult.fail("target is blank" ); if (req.content() == null || req.content().isBlank()) return NotifyResult.fail("content is blank" ); try { return registry.get(type).send(req); } catch (Exception e) { return NotifyResult.fail("send failed: " + e.getMessage()); } } }
现在就可以直接
选择策略:registry.get(type)
执行:send(…)
3. 这个模式带来的好处
消灭一堆 if/else,逻辑更清晰
新增策略不改老代码(符合开闭原则:对扩展开放,对修改关闭)
每个策略可单测,测试粒度更细
更容易做“按配置动态启用策略”
这个暂时就这样了,后续我补上一些图,可能会更明显,敬请期待。