策略模式(学习笔记, 2021.5.11)
前言:
在策略模式(Strategy Pattern) 中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
**意图:**定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
**主要解决:**在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
**何时使用:**一个系统有许多许多类,而区分它们的只是他们直接的行为。
**如何解决:**将这些算法封装成一个一个的类,任意地替换。
**关键代码:**实现同一个接口。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
**注意事项:**如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
解决的场景:
根据之前笔记设计模式学习注意点上的例子
如果后面公司突然来了需求, 说要求广州鸭子与湛江鸭子在某个时段也都会游泳了或者都会飞, 在其他时段又不会游泳会飞, 那是不是需要每次都使用大量
if
进行判断, 后续维护不太方便。例如下面:
改造广州/湛江鸭子
/**
* @Author: ZhiHao
* @Date: 2021/5/11 10:37
* @Description: 广州鸭子
* @Versions 1.0
**/
public class GuangZhouDuck implements Fly,Swimming {
@Override
public String fly(String name) {
return name+"会飞";
}
@Override
public String swimming(String name) {
return name+"会游泳";
}
}
// ----------------------------------------------------------------------------------------
/**
* @Author: ZhiHao
* @Date: 2021/5/11 10:52
* @Description: 湛江鸭子
* @Versions 1.0
**/
public class ZhanJiangDuck implements Fly,Swimming {
@Override
public String fly(String name) {
return name + "会飞";
}
@Override
public String swimming(String name) {
return name+"游泳";
}
}
进行判断测试
@Test
public void contextLoads() throws Exception {
// 广州鸭子
GuangZhouDuck guangZhouDuck = new GuangZhouDuck();
// 湛江鸭子
ZhanJiangDuck zhanJiangDuck = new ZhanJiangDuck();
// 条件
int condition = 3;
// 判断什么时间段, 什么鸭子可以游泳或者飞
if (1 == condition){
System.out.println(guangZhouDuck.fly("一号时间段广州鸭子"));
System.out.println(zhanJiangDuck.swimming("一号时间段湛江鸭子"));
}
if (2 == condition){
System.out.println(guangZhouDuck.fly("二号时间段湛江鸭子"));
System.out.println(zhanJiangDuck.swimming("二号时间段广州鸭子"));
}
if (3 == condition){
System.out.println(guangZhouDuck.fly("三号湛江鸭子都"));
System.out.println(guangZhouDuck.swimming("三号湛江鸭子都"));
System.out.println(zhanJiangDuck.swimming("三号广州鸭子都"));
System.out.println(zhanJiangDuck.fly("三号广州鸭子都"));
}
}
这种, 后续条件越来越多的情况下, 会变的越来越难以维护
使用策略模式进行优化
1.0 改造鸭子实体
/**
* @Author: ZhiHao
* @Date: 2021/5/11 10:37
* @Description: 广州鸭子
* @Versions 1.0
**/
public class GuangZhouDuck implements Fly,Swimming {
@Override
public String fly(String name) {
return "广州"+name+"会飞";
}
@Override
public String swimming(String name) {
return "广州"+name+"会游泳";
}
}
//------------------------------------------------------------------------------------
/**
* @Author: ZhiHao
* @Date: 2021/5/11 10:52
* @Description: 湛江鸭子
* @Versions 1.0
**/
public class ZhanJiangDuck implements Fly,Swimming {
@Override
public String fly(String name) {
return "湛江"+name + "会飞";
}
@Override
public String swimming(String name) {
return "湛江"+name+"游泳";
}
}
2.0 创建策略鸭子基类
/**
* @Author: ZhiHao
* @Date: 2021/5/11 14:42
* @Description: 策略鸭子基类, 继承DuckBase( 拥有吃与叫行为 ), 在实现飞与游泳接口( 让其子类必须实现 )
* @Versions 1.0
**/
public abstract class StrategyDuckBase extends DuckBase implements Fly, Swimming {
public GuangZhouDuck guangZhouDuck;
public ZhanJiangDuck zhanJiangDuck;
/**
* 初始化广州/湛江鸭子
*
* @author: ZhiHao
* @date: 2021/5/11
*/
public StrategyDuckBase() {
this.guangZhouDuck = new GuangZhouDuck();
this.zhanJiangDuck = new ZhanJiangDuck();
}
/**
* 获取对应条件, 鸭子能做什么行为的实现类
*
* @param number
* @return com.zhihao.design.base.StrategyDuckBase
* @author: ZhiHao
* @date: 2021/5/11
*/
public static StrategyDuckBase returnAccordWithDuck(int number){
return Condition.findDuckByNumber(number);
}
}
3.0 创建多种对应条件的子类
/**
* @Author: ZhiHao
* @Date: 2021/5/11 14:50
* @Description: 一号鸭子能做的行为
* @Versions 1.0
**/
public class No1Duck extends StrategyDuckBase {
@Override
public String fly(String name) {
// 广州鸭子
return super.guangZhouDuck.fly(name);
}
/**
* 一号时间段湛江鸭子游泳
*
* @param name
* @return java.lang.String
* @author: ZhiHao
* @date: 2021/5/11
*/
@Override
public String swimming(String name) {
// 湛江鸭子
return super.zhanJiangDuck.swimming(name);
}
}
//---------------------------------------------------------------------------------------------
/**
* @Author: ZhiHao
* @Date: 2021/5/11 14:50
* @Description: 二号鸭子能做的行为
* @Versions 1.0
**/
public class No2Duck extends StrategyDuckBase {
@Override
public String fly(String name) {
return super.zhanJiangDuck.fly(name);
}
@Override
public String swimming(String name) {
return super.guangZhouDuck.swimming(name);
}
}
//---------------------------------------------------------------------------------------------
/**
* @Author: ZhiHao
* @Date: 2021/5/11 14:50
* @Description: 三号鸭子能做的行为
* @Versions 1.0
**/
public class No3Duck extends StrategyDuckBase{
@Override
public String fly(String name) {
return super.zhanJiangDuck.fly(name) + ","+super.guangZhouDuck.fly(name+"也");
}
@Override
public String swimming(String name) {
return super.zhanJiangDuck.swimming(name)+","+super.guangZhouDuck.swimming(name+"也");
}
}
4.0 定义根据条件获取对应实例的枚举
/**
* @Author: ZhiHao
* @Date: 2021/5/11 15:13
* @Description: 根据条件获取实例
* @Versions 1.0
**/
public enum Condition {
NO1_DUCK(1, No1Duck::new),
NO2_DUCK(2, No2Duck::new),
NO3_DUCK(3, No3Duck::new),
;
private Integer number;
private Supplier<StrategyDuckBase> supplier;
Condition(Integer number, Supplier<StrategyDuckBase> supplier) {
this.number = number;
this.supplier = supplier;
}
/**
* 通过条件返回对应实例
*
* @param number
* @return com.zhihao.design.base.StrategyDuckBase
* @author: ZhiHao
* @date: 2021/5/11
*/
public static StrategyDuckBase findDuckByNumber(Integer number) {
return Arrays.stream(values()).filter(condition -> condition.number.equals(number))
.findAny().orElseThrow(RuntimeException::new).supplier.get();
}
}
5.0 进行测试
@Test
public void contextLoads() throws Exception {
// 条件1
int condition = 1;
StrategyDuckBase duckBase1 = StrategyDuckBase.returnAccordWithDuck(condition);
System.out.println(duckBase1.fly("鸭子"));
System.out.println(duckBase1.swimming("鸭子"));
System.out.println("----------------------------------------------------");
// 条件2
condition = 2;
StrategyDuckBase duckBase2 = StrategyDuckBase.returnAccordWithDuck(condition);
System.out.println(duckBase2.fly("鸭子"));
System.out.println(duckBase2.swimming("鸭子"));
System.out.println("----------------------------------------------------");
// 条件3
condition = 3;
StrategyDuckBase duckBase3 = StrategyDuckBase.returnAccordWithDuck(condition);
System.out.println(duckBase3.fly("鸭子"));
System.out.println(duckBase3.swimming("鸭子"));
}
广州鸭子会飞
湛江鸭子游泳
----------------------------------------------------
湛江鸭子会飞
广州鸭子会游泳
----------------------------------------------------
湛江鸭子会飞,广州鸭子也会飞
湛江鸭子游泳,广州鸭子也会游泳
策略模式使用完毕, 代码简洁多了, 后续在增加时间段条件, 只需要新创建一个
No4Duck
实现类, 方法里面写具体逻辑, 并添加入枚举里面即可在运行时候, 根据动态参数获取对应条件实例进行执行。
1