基本介绍
策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,是一种对象行为型模式。
模式结构
Context(环境角色):持有抽象策略角色的引用
Strategy(抽象策略角色):给出所有具体策略类所需的接口
ConcreteStrategy(具体策略角色):包装了相关的算法或行为
举例说明
鸭子分为野生和家养,野生鸭子会飞,而家养鸭子不会飞。使用策略模式来是实现,可以将「飞」定义为一个抽象策略,具体策略就是「会飞」、「不会飞」
1、抽象策略角色
public interface FlyBehavior {
void fly();
}
2、具体策略角色
public class CanFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("可以飞");
}
}
public class NotFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("不会飞");
}
}
3、环境角色
//鸭子类
public abstract class Duck {
private FlyBehavior flyBehavior;
public Duck(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void fly(){
flyBehavior.fly();
}
public abstract void description();
}
//野生鸭子
public class WildDuck extends Duck {
public WildDuck(FlyBehavior flyBehavior) {
super(flyBehavior);
}
@Override
public void description() {
System.out.println("我是野生鸭子");
}
}
//家养鸭子
public class DomesticDuck extends Duck {
public DomesticDuck(FlyBehavior flyBehavior) {
super(flyBehavior);
}
@Override
public void description() {
System.out.println("我是家养鸭子");
}
}
4、测试类
public class Client {
@Test
public void test(){
Duck duck1 = new WildDuck(new CanFlyBehavior());
duck1.description();
duck1.fly();
Duck duck2 = new DomesticDuck(new NotFlyBehavior());
duck2.description();
duck2.fly();
}
}
5、运行结果
我是野生鸭子
可以飞
我是家养鸭子
不能飞
模式分析
优点:
- 易于扩展。策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
- 策略模式提供了管理相关的算法族的办法。
- 使用聚合或组合替换了继承,降低耦合。
- 使用策略模式可以避免使用多重条件转移语句。
缺点:
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
- 可能会产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。
适用场景:
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
- 不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。
参考:https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/strategy.html