策略模式对一系列的算法加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择由客户端决定使用哪种策略。策略模式主要用来处理算法的切换。
在我们的生活中我们可以通过很多种不同的方式来完成一件事情,这里的每一种方式都可以称作为一种策略。我们可以根据环境、条件等因素的不同选择不同的策略来完成这件事情。比如马上过年回家了,我们可以选择坐火车、坐飞机、坐大巴、开车,骑自行车等等方式。如果想舒适快速我们可以选择飞机,节约钱我们可以选择火车和大巴,离家近的我们可以骑自行车,每一种方式都可以到达目的地。
在软件开发过程中是一样的,我们可能有很多种方法可以实现某一个功能,但是我们需要一种简单、高效的途径可以使得系统能够灵活的解决问题。这就是策略模式的设计动机。
下图为策略模式的结构:
这个模式涉及到三个角色:
● 环境(Context)角色:持有一个Strategy的引用。
● 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
● 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
例子我们都知道加密算法有很多种,首先我们需要定义一个接口,该接口提供加密算法,然后定义具体想要的加密算法,实现接口即可。
接口定义了抽象的加密算法,所有的加密算法都应该实现该接口。
public interface Strategy {
//加密
public void encrypt();
}
public class MD5Sreategy implements Strategy{
@Override
public void encrypt(){
System.out.println("执行MD5加密");
}
}
public class MDSStrategy implements Strategy {
@Override
public void encrypt() {
System.out.println("执行MDS加密");
}
}
public static void main(String[] args) {
Strategy strategy=new MD5Sreategy();
strategy.encrypt();
}
运行结果:
执行MD5加密
而策略模式还有一个核心context,它类似于一个工厂,里面包含了Strategy 的引用,而我们可以动态地传入Strategy,实现算法的加密
public class Context {
private Strategy strategy;
public Context() {
}
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void encrypt(){
this.strategy.encrypt();
}
}
public static void main(String[] args) {
Context context=new Context(new MD5Sreategy());
context.encrypt();
}
运行结果:
执行MD5加密
临近过节,商家为了业绩大搞促销活动,某店提出促销优惠方案:全场八折,
public interface Strategy {
public double cost(double num);
}
public class StrategyA implements Strategy {
@Override
public double cost(double num) {
return 0.8*num;
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public Context(){
}
public double cost(double num){
return this.strategy.cost(num);
}
}
public static void main(String[] args) {
Context context=new Context(new StrategyA());
double cost = context.cost(200);
System.out.println("实际付账"+cost);
}
运行结果:
实际付账160.0
活动推出两天,老板一看不对劲了,优惠过大自己没有利润可赚怎么能行,于是有改变了促销优惠方案:
满200减50
public class StrategyB implements Strategy {
@Override
public double cost(double num) {
if (num >= 200) {
return num - 50;
}
return num;
}
}
public static void main(String[] args) {
Context context=new Context(new StrategyB());
double cost = context.cost(200);
System.out.println("实际付账"+cost);
}
运行结果:
实际付账150.0
策略模式与状态模式是非常的相似,就犹如一对双胞胎一样。只不过状态模式是通过改变对象内部的状态来帮助对象控制自己的行为,用户无法指定状态,最多只能设置初始状态。 而策略模式则是围绕可以互换的算法来创建成功业务的。
主要优点(1)提供了对开闭原则的完美支持,用户可以在不修改原有系统的基础上选择具体算法或行为,也可以灵活地增加新的算法或行为。
(2)避免了多重的if-else条件选择语句,利于系统的维护。
(3)提供了一种算法的复用机制,不同的环境类可以方便地复用这些策略类。
主要缺点(1)客户端需要知道所有的策略类,并自行决定使用哪一个策略 => 只适用于客户端了解所有策略算法的情况。
(2)将造成系统产生很多的具体策略类,任何细小的变化都将导致系统要增加一个具体策略类 => 类的个数也许会超出预期。
(3)无法在客户端同时使用多个策略类 => 客户端每次只能使用一个策略类。
应用场景(1)如果一个系统要动态地在几种算法之间选择其中一种 => 那就快用策略模式吧!
(2)如果有难以维护的多重if-else条件选择语句是为了实现对象的行为 => 那就快用策略模式吧!
(3)不希望客户知道复杂的与算法有关的数据结构,可以将其封装到策略中 => 提高算法的保密性和安全性!
场景实例:
2个经典应用的Spring中策略模式
实际项目运用之Strategy模式(策略模式)
感兴趣的可以去看看