相信自己,请一定要相信自己
上一章简单介绍了状态模式(二十四), 如果没有看过, 请观看上一章
一. 策略模式
引用 菜鸟教程里面 策略模式介绍: https://www.runoob.com/design-pattern/strategy-pattern.html
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。
这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。
策略对象改变 context 对象的执行算法。
一.一 介绍
意图: 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决: 在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
何时使用: 一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决: 将这些算法封装成一个一个的类,任意地替换。
关键代码: 实现同一个接口。
应用实例:
1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。
2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。
3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景:
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2、一个系统需要动态地在几种算法中选择一种。
3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注意事项: 如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
组成角色 | 具体 | 关系 |
抽象策略角色 (Strategy) | FlyBehavior | 这个是一个抽象的角色,通常情况下使用接口或者抽象类去实现 |
具体策略角色 | NoFly, BadFly | 包装了具体的算法和行为 |
环境角色(Context) | DuckContext | 内部会持有一个抽象角色的引用,给客户端调用 |
二. 策略模式实例
二.一 飞实例一
二.一.一 抽象策略角色 FlyBehavior
public interface FlyBehavior {
void fly();
}
二.一.二 具体策略
飞得好:
@Slf4j
public class GoodFly implements FlyBehavior{
@Override
public void fly() {
log.info("飞的非常好");
}
}
飞得差:
@Slf4j
public class BadFly implements FlyBehavior{
@Override
public void fly() {
log.info("飞的很差");
}
}
不会飞:
@Slf4j
public class NoFly implements FlyBehavior{
@Override
public void fly() {
log.info("不能飞");
}
}
二.一.三 环境角色和实现 AbstractDuckContext
@Slf4j
@Data
public abstract class AbstractDuckContext {
private FlyBehavior flyBehavior;
public AbstractDuckContext (FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
/**
定义了公共的方法
*/
public void speak(){
log.info("可以叫");
}
public void swim() {
log.info("可以游泳");
}
public void fly() {
if (flyBehavior != null) {
flyBehavior.fly();
}
}
}
public class TianE extends AbstractDuckContext {
public TianE(FlyBehavior flyBehavior){
super(flyBehavior);
}
}
二.一.四 客户端调用
@Test
public void oneTest() {
AbstractDuckContext tianE = new TianE(new GoodFly());
tianE.fly();
log.info(">>>>> 这只天鹅受伤了");
// 设置一下
tianE.setFlyBehavior(new BadFly());
tianE.getFlyBehavior().fly();
log.info(">>>>> 这只天鹅翅膀被人打断了");
tianE.setFlyBehavior(new NoFly());
tianE.getFlyBehavior().fly();
}
二.二 计算方式策略
二.二.一 抽象角色 CalcStrategy
public interface CalcStrategy {
int calc(int num1, int num2);
}
二.二.二 具体角色实现
相加:
public class AddStrategy implements CalcStrategy{
@Override
public int calc(int num1, int num2) {
return num1 + num2;
}
}
相减:
public class SubStrategy implements CalcStrategy{
@Override
public int calc(int num1, int num2) {
return num1 - num2;
}
}
二.二.三 上下文处理 CalcStrategyContext
public class CalcStrategyContext {
private CalcStrategy calcStrategy;
public CalcStrategyContext (CalcStrategy calcStrategy) {
this.calcStrategy = calcStrategy;
}
public void setCalcStrategy(CalcStrategy calcStrategy) {
this.calcStrategy = calcStrategy;
}
// 定义原先的方法
public int calc(int num1, int num2) {
return this.calcStrategy.calc(num1,num2);
}
}
二.二.四 客户端调用
@Test
public void twoTest() {
CalcStrategyContext calcStrategyContext = new CalcStrategyContext(new AddStrategy());
int calc = calcStrategyContext.calc(5, 1);
log.info(">>> 加法: {}", calc);
calcStrategyContext.setCalcStrategy(new SubStrategy());
calc = calcStrategyContext.calc(5, 1);
log.info(">>> 减法: {}", calc);
}
INFO [main] (StrategyTest.java:36) - >>> 加法: 6
INFO [main] (StrategyTest.java:40) - >>> 减法: 4