在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
介绍
什么是策略模式(Strategy Pattern)
在软件开发过程中常常遇到这样的情况, 实现某一个功能有很多种算法或实现策略, 我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能. 如果将这些算法或者策略抽象出来, 提供一个统一的接口, 不同的算法或者策略有不同的实现类, 这样在程序客户端就可以通过注入不同的实现对象来实现算法或者策略的动态替换, 这种模式的可扩展性和可维护性也更高, 这就是策略模式.
策略模式的定义(Strategy Pattern)
策略模式: 定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立与使用算法的客户.(摘抄于Head First设计模式)
简单理解: 定义了一系列算法,每个算法封装起来,各个算法之间可以互相替换,且算法的变化不会影响到使用算法的客户,属于行为型模式.
使用场景
- 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时;
- 需要安全的封装多种同一类型的操作时;
- 出现同一抽象类有多个字类, 而有需要使用 if-else 或者 switch-case 来选择具体字类时;
例如:
或出现大量 if-else 判断时可以使用策略模式优化代码.
例如电商网站支付方式,一般分为银联,微信,支付宝,可以采用策略模式,每一种方式作为一种支付方式的实现,如果哪一个支付方式发生变化,只需要修改对应的实现即可,不需要修改调用的客户端,如果引入新的支付方式,如:随行付,则只需要增加一个对应的随行付实现类即可,遵循开闭原则.
组成部分(三个角色)
1. 抽象策略(Strategy):
通常由接口或抽象类实现. 定义了多个具体策略的公共接口, 具体策略中各种不同的算法以不同的方式实现这个接口; Context使用这些接口调用不同实现的算法.
2. 具体策略(ConcreteStrategy):
实现了Strategy接口或继承与抽象类, 封装了具体的算法和行为.
3. 环境类(Context):
持有一个公共策略接口的引用(Strategy), 直接给客户端调用.
优缺点及重点
优点:
- 每个算法单独封装, 减少算法与算法调用者之间的耦合;
- 算法可以*切换;
- 避免使用多重条件判断;
- 扩展性良好;
缺点:
- 策略类会增多.
- 所有策略类都需要对外暴露.
重点
- 给对象传入什么样的策略, 就执行什么样的动作.
实现
类图
说明: 代码来自Head First设计模式中SimUDuck的示例.
代码结构:
抽象策略(Strategy):
/**
* 飞行行为
*/
public interface FlyBehavior {
//各种飞行实现
public void fly();
}
具体策略(ConcreteStrategy):
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("I'm flying!");
}
}
环境类(Context):
/**
* 鸭子类
*/
public abstract class Duck {
//持有一个公共策略接口的引用
public FlyBehavior flyBehavior;
public QuackBehavior quackBehavior;
public void swim() {
System.out.println("我会游泳...");
}
public abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
//提供set方法, 使鸭子可以动态改变飞行策略
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
//提供set方法, 使鸭子可以动态改变叫声策略
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
/**
* 绿头鸭
*/
public class MallardDuck extends Duck {
@Override
public void display() {
System.out.println("绿头鸭");
}
public MallardDuck() {
/*MallardDuck 继承 Duck, 所以具有quackBehavior 和 flyBehavior实例变量
当MallardDuck实例化时, 它的构造器会把继承的quackBehavior,
flyBehavior实例变量初始化成Quack,FlyWithWings类型的新实例
*/
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
}
测试类:
public static void main(String[] args) {
Duck mallard = new MallardDuck();
//飞行
mallard.performFly();
//改变鸭子行为(传入飞行策略)
mallard.setFlyBehavior(new FlyRocketPowered());
mallard.performFly();
//叫声
mallard.performQuack();
}
执行结果:
I'm flying!
I'm flying with a rocket!
呱呱叫
生活中的策略模式(我的猜想)
俗话说: 人是铁饭是钢, 一顿不吃饿的慌;吃饭也有策略模式, 你晓得嘛.
人(环境类)饿了要吃饭(抽象策略), 但是吃什么你知道吗? 这时你的大脑就会调集你的毕生功力(经验, 生活经历, 常识等等),来知道有哪些东西是可以吃的,比如鸡腿,面包或粥等等(具体策略,暴露所有策略).大脑选择(动态选择策略)吃其中的一种或多种食物来应对身体的不满.
生活中这样的例子还有很多,网上购物(不同的商品即: 具体策略), 世界那么大, 我想去转转.(转转的方式即: 具体策略)等.
结语
设计模式源于生活