策略模式
策略模式(Strategy Pattern)也叫政策模式。是一种比较简单的模式。
1策略模式的定义
策略模式的英文原文是:
Define a family of algorithms,encapsulate each one,and make them interchangeable.
意思是:
定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。
其用意是针对一组算法,将每一个算法封装到具有共同接口的独立类中,从而使得他们可以相互替换,社的算法可以在不影响到客户端的情况下发生变化。
策略模式设计以下3个角色。
- 环境(Context)角色:该角色也叫上下文角色,起承上启下的作用,屏蔽高层模块对策略、算法的直接访问,它持有一个strategy类的引用。
- 抽象策略(Strategy)角色:该角色对策略、算法进行抽象,通常定义每个策略或算法必须具有的方法和属性。
- 具体策略(Concrete Strategy)角色:该角色实现抽象策略中的具体操作,含有具体的算法。
策略模式的类图
创建抽象策略
Strategy.java
package com.eric.行为型模式.策略模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 抽象策略
* @CreateTime 2020-12-07 19:25:19
*/
public abstract class Strategy {
//策略方法
public abstract void strategyInterface();
}
创建具体抽象策略
ConcreteStrategy.java
package com.eric.行为型模式.策略模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 具体策略
* @CreateTime 2020-12-07 19:26:23
*/
public class ConcreteStrategy extends Strategy {
//实现策略方法
@Override
public void strategyInterface() {
//具体算法
}
}
创建环境角色(上下文类)
Context.java
package com.eric.行为型模式.策略模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 环境角色
* @CreateTime 2020-12-07 19:27:19
*/
public class Context {
private Strategy strategy = null;
//构造函数
public Context(Strategy strategy)
{
this.strategy =strategy;
}
//调用策略方法
public void contextInterface()
{
this.strategy.strategyInterface();
}
}
2策略模式的应用
a.策略模式的优点
- 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当的使用继承可以把公共的代码移到父类中,从而避免代码重复。
- 策略模式提供了可以替代继承关系的办法。继承可以处理多种算法或行为,如果不用策略模式,那么使用算法或行为的环境类就有可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样算法或行为的使用者就和算法本身混在一起,从而不可能再独立演化。
- 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,这比使用继承的办法还要原始和落后。
b.策略模式的缺点
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类,即策略模式只适用于客户端知道所有的算法和行为的情况。
- 策略模式很有可能造成大量的策略类在项目中。有时候可以通过依赖于环境的状态保持到客户端里面,而将策略类设计成可共享的,这样策略类实例,可以被不同的客户端使用。可以使用享元模式来减少对象的数量。
c.策略模式的应用场景
- 多个类只是在算法或行为上稍有不同的场景。
- 算法需要自由切换。
- 需要屏蔽算法规则的场景。
3策略模式的实例
使用策略模式演示图书销售中不同的折扣算法。
package com.eric.行为型模式.策略模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 抽象折扣算法
* @CreateTime 2020-12-09 08:40:52
*/
public abstract class DiscountStrategy {
//书的价格
private double price = 0;
//书的数量
private int number = 0;
//构造函数
public DiscountStrategy(double price,int number){
this.price = price;
this.number = number;
}
public double getPrice() {
return price;
}
public int getNumber() {
return number;
}
//策略方法,计算折扣
public abstract double calculateDiscount();
}
创建具体算法,均继承DiscountStrategy
NoDiscountStrategy.java
package com.eric.行为型模式.策略模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 具体折扣算法,没有折扣
* @CreateTime 2020-12-09 08:48:17
*/
public class NoDiscountStrategy extends DiscountStrategy{
public NoDiscountStrategy(double price, int number) {
super(price, number);
}
//实现折扣算法,无折扣
@Override
public double calculateDiscount() {
return 0;
}
}
FixDiscountStrategy.java
package com.eric.行为型模式.策略模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 具体折扣算法,固定值为1的算法
* @CreateTime 2020-12-09 08:49:38
*/
public class FixDiscountStrategy extends DiscountStrategy {
public FixDiscountStrategy(double price, int number) {
super(price, number);
}
@Override
public double calculateDiscount() {
//数量*固定的1元折扣=折扣总钱数
return getNumber();
}
}
PercentageDiscountStrategy.java
package com.eric.行为型模式.策略模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 具体折扣算法,优惠百分比为15%
* @CreateTime 2020-12-09 08:53:00
*/
public class PercentageDiscountStrategy extends DiscountStrategy {
public PercentageDiscountStrategy(double price, int number) {
super(price, number);
}
@Override
public double calculateDiscount() {
//总钱数*15%=优惠总钱数
return getNumber() * getPrice() * 0.15;
}
}
创建环境类
ContextClient.java
package com.eric.行为型模式.策略模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 环境角色
* @CreateTime 2020-12-09 08:54:32
*/
public class ContextClient {
private DiscountStrategy discountStrategy;
private ContextClient(DiscountStrategy discountStrategy)
{
this.discountStrategy = discountStrategy;
}
public double ContextCalDisc()
{
return discountStrategy.calculateDiscount();
}
public static void main(String[] args) {
ContextClient contextNoDiscountStrategy = new ContextClient(new NoDiscountStrategy(30, 30));
System.out.println("0折扣:"+contextNoDiscountStrategy.ContextCalDisc());
ContextClient contextFixDiscountStrategy = new ContextClient(new FixDiscountStrategy(30, 30));
System.out.println("固定1元折扣:"+contextFixDiscountStrategy.ContextCalDisc());
ContextClient contextPercentageDiscountStrategy= new ContextClient(new PercentageDiscountStrategy(30, 30));
System.out.println("15%折扣:"+contextPercentageDiscountStrategy.ContextCalDisc());
}
}
测试结果
可以看出,通过不过使用不同的策略,但相同的方法,实现了对图书的优惠不同的计算。