在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如,出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等,超市促销可以釆用打折、送商品、送积分等方法。
在软件开发中,当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。
如果使用多重条件转移语句实现(即硬编码),不但使条件语句变得很复杂,而且增加、删除或更换算法要修改原代码,不易维护,违背开闭原则。如果采用策略模式就能很好解决该问题。
一、策略模式 1、策略模式的定义策略(Strategy Pattern)模式,又叫作政策模式(P玻璃窗与Pattern):
该模式定义了一系列算法,并将每个算法分别封装起来,让它们之间可以相互替换,从而让算法的变化不会影响使用算法的客户。 策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
策略模式使用的是面向对象的继承和多态机制,从而实现同一行为在不同的场景下具备不同的实现。
2、策略模式的结构策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面,作为一个抽象策略类的子类。策略模式的重心不是如何实现算法,而是如何组织这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性,现在我们来分析其基本结构和实现方法。
(1)模式的结构
主要角色如下:
- 抽象策略角色(Strategy):定义策略或者算法的行为。各种不同的算法以不同的方式实现这个接口,上下文角色使用这个接口调用不同的算法,一般是一个公共接口或抽象类。
- 具体策略角色(Concrete Strategy):实现了抽象策略接口,提供具体的策略或者算法实现。
- 上下文角色(Context):持有一个策略类的引用,最终给客户端调用。
上下文角色的职责是:隔离客户端与策略类的耦合,让客户端完全与上下文角色访问,客户端不需要关心具体策略。
(2)结构图如下:(图来自网络)
主要优点如下:
- 避免使用多重条件转移语句不,如 if…else 语句、switch…case 语句。
- 策略模式符合开闭原则。
- 使用策略模式可以提高算法的保密性和安全性。
主要缺点如下:
- 客户端必须理解所有的策略或者算法,并且可以自行决定使用哪一个策略类。
- 策略模式造成很多的策略类,增加维护难度。
- 针对同一类型问题,有多种处理方式,每一种都能独立解决问题
- 需要自由切换算法的场景
- 需要屏蔽算法规则的场景
代码如下:
public class StrategyPattern {
public static void main(String[] args) {
Context c = new Context();
Strategy s = new ConcreteStrategyA();
c.setStrategy(s);
c.strategyMethod();
System.out.println("-----------------");
s = new ConcreteStrategyB();
c.setStrategy(s);
c.strategyMethod();
}
}
//抽象策略类
interface Strategy {
void strategyMethod(); //策略方法
}
//具体策略类A
class ConcreteStrategyA implements Strategy {
@Override
public void strategyMethod() {
System.out.println("具体策略A的策略方法被访问!");
}
}
//具体策略类B
class ConcreteStrategyB implements Strategy {
@Override
public void strategyMethod() {
System.out.println("具体策略B的策略方法被访问!");
}
}
//上下文类
class Context {
private Strategy strategy;
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void strategyMethod() {
strategy.strategyMethod();
}
}
策略模式与单例模式或者工厂模式等其他模式使用功能,更提高代码的健壮性,优化代码。
这里用订单支付场景为例。
1、支付状态信息的包装类public class MsgResult {
private int code;
private Object data;
private String msg;
public MsgResult(int code, Object data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
}
@Override
public String toString() {
return "MsgResult{" +
"code=" + code +
", data=" + data +
", msg='" + msg + '\'' +
'}';
}
2、抽象策略类:支付渠道
public abstract class Payment {
// 获取支付方式的名字
public abstract String getName();
// 查询余额
public abstract double queryBalance(String uid);
// 通用的支付逻辑方法,这里简单点。具体的支付方法可以写个钩子方法,放到子类去实现。
public MsgResult pay(String uid, double amount){
if(queryBalance(uid)
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?