什么是策略模式
定义一系列算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法可以独立于使用它的客户端而变化。
策略模式结构
1)抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有具体策略类所需的接口。
2)具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
3)环境或上下文(Context)类:是使用算法的角色,持有一个策略类的引用,最终给客户端调用。
代码示例:
package main.java.cn.test.strategy.V1;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:28:43
* @description
*/
public interface Strategy {
void algorithm();
}
package main.java.cn.test.strategy.V1;
import main.java.cn.test.strategy.V1.Strategy;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:29:10
* @description
*/
public class ConcreteStrategyA implements Strategy {
@Override
public void algorithm(){
System.out.println("执行策略A");
}
}
package main.java.cn.test.strategy.V1;
import main.java.cn.test.strategy.V1.Strategy;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:29:49
* @description
*/
public class ConcreteStrategyB implements Strategy {
@Override
public void algorithm() {
System.out.println("执行策略B");
}
}
package main.java.cn.test.strategy.V1;
import main.java.cn.test.strategy.V1.Strategy;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:30:13
* @description
*/
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
// 调用策略类中的算法
public void algorithm(){
strategy.algorithm();
}
}
package main.java.cn.test.strategy.V1;
import main.java.cn.test.strategy.V1.ConcreteStrategyA;
import main.java.cn.test.strategy.V1.Context;
import main.java.cn.test.strategy.V1.Strategy;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:30:31
* @description
*/
public class Client {
public static void main(String [] args){
Strategy strategyA = new ConcreteStrategyA();
// 具体策略类,可以在运行时指定类型,通过配置文件+反射机制实现
Context context = new Context(strategyA);
context.algorithm();
}
}
优点
1)易于扩展和维护。由于不同的算法被封装在不同的类中,所以我们可以很容易地添加新的算法或修改已有算法,而不需要修改客户端的代码。
2)提高代码的可读性。将不同的算法封装在不同的类中,使得代码更加模块化,易于理解和维护。
3)可以消除大量的条件语句。使用策略模式,我们可以将不同的算法替换成不同的类,从而消除大量的if-else语句,使得代码更加简洁和易于理解。
缺点
1)需要额外的类和接口。使用策略模式,我们需要为每个算法都创建一个独立的类,从而增加了代码的复杂度。
2)客户端需要知道所有的策略类。使用策略模式,客户端需要知道所有的策略类,以便在运行时选择合适的策略。这可能会增加代码的复杂度。
应用场景
1)需要根据不同的条件选择不同的算法时。例如,计算器程序需要根据用户输入的运算符选择相应的计算方法。
2)需要在运行时动态地选择算法时。例如,某个系统需要根据用户的配置或环境变量来选择合适的算法。
3)需要将算法的实现细节与客户端代码分离时。例如,某个系统需要根据不同的数据来源来解析数据,但是客户端并不关心数据的解析细节。
应用:策略模式优化if-else代码
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:34:56
* @description 定义策略接口
*/
public interface AuditStrategy {
// 判断条件是否匹配
public boolean isSupport(LeaveForm leaveForm);
// 审核业务逻辑
public void audit(LeaveForm leaveForm);
// 规则冲突优先级
public int getPriority();
// 规则名称
public String getName();
}
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:35:56
* @description 策略实现1
*/
public class AuditStrategyImpl_1 implements AuditStrategy{
@Override
public boolean isSupport(LeaveForm leaveForm) {
return leaveForm.getDays() <= 3 && leaveForm.getType() == 1;
}
@Override
public void audit(LeaveForm leaveForm) {
System.out.println(leaveForm);
System.out.println("三天以下婚丧假 无需审批自动通过!");
}
@Override
public int getPriority() {
return 0;
}
@Override
public String getName() {
return "三天以下婚假审批规则";
}
}
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:36:32
* @description 策略实现2
*/
public class AuditStrategyImpl_2 implements AuditStrategy{
@Override
public boolean isSupport(LeaveForm leaveForm) {
return leaveForm.getDays() > 3 && leaveForm.getType() == 1;
}
@Override
public void audit(LeaveForm leaveForm) {
System.out.println(leaveForm);
System.out.println("三天以上婚丧假 进入上级审批流程!");
}
@Override
public int getPriority() {
return 0;
}
@Override
public String getName() {
return "三天以上婚丧假审批规则";
}
}
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:36:59
* @description 策略实现3
*/
public class AuditStrategyImpl_3 implements AuditStrategy{
@Override
public boolean isSupport(LeaveForm leaveForm) {
//级别9 总经理
return leaveForm.getEmployee().getLevle().equals(9);
}
@Override
public void audit(LeaveForm leaveForm) {
System.out.println(leaveForm);
System.out.println("总经理请假无需审批自动通过!");
}
@Override
public int getPriority() {
return 999;
}
@Override
public String getName() {
return "总经理请假审批规则";
}
}
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:48:27
* @description 策略实现4
*/
public class AuditStrategyImpl_4 implements AuditStrategy{
@Override
public boolean isSupport(LeaveForm leaveForm) {
return leaveForm.getDays() > 3 && leaveForm.getType() == 0;
}
@Override
public void audit(LeaveForm leaveForm) {
System.out.println(leaveForm);
System.out.println("三天以上病假 进入上级审批流程!");
}
@Override
public int getPriority() {
return 0;
}
@Override
public String getName() {
return "三天以上病假审批规则";
}
}
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:49:19
* @description 策略实现5
*/
public class AuditStrategyImpl_5 implements AuditStrategy{
@Override
public boolean isSupport(LeaveForm leaveForm) {
return leaveForm.getDays() <= 3 && leaveForm.getType() == 0;
}
@Override
public void audit(LeaveForm leaveForm) {
System.out.println(leaveForm);
System.out.println("三天以下病假 无需审批自动通过!");
}
@Override
public int getPriority() {
return 0;
}
@Override
public String getName() {
return "三天以下病假假审批规则";
}
}
package main.java.cn.test.strategy.V2;
import java.util.ArrayList;
import java.util.List;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:39:21
* @description 策略工厂
*/
public class AuditStrategyFactory {
//私有静态全局唯一 工厂对象
private final static AuditStrategyFactory factory = new AuditStrategyFactory();
//使用集合存储策略信息
private List<AuditStrategy> auditStrategyList = new ArrayList<>();
//私有构造,用于注册规则
private AuditStrategyFactory(){
auditStrategyList.add(new AuditStrategyImpl_1());
auditStrategyList.add(new AuditStrategyImpl_2());
auditStrategyList.add(new AuditStrategyImpl_3());
auditStrategyList.add(new AuditStrategyImpl_4());
auditStrategyList.add(new AuditStrategyImpl_5());
}
//全局访问点 获取单例对象
public static AuditStrategyFactory getInstance(){
return factory;
}
//获取匹配的策略
public AuditStrategy getAuditStrategy(LeaveForm leaveForm){
AuditStrategy auditStrategy = null;
for (AuditStrategy strategy : auditStrategyList) {
//找到匹配的规则
if(strategy.isSupport(leaveForm)){
if(auditStrategy == null){
auditStrategy = strategy;
}else{
//优先级高的规则 替换现有的规则
//例如: 总经理请病假10,总经理优先级999,普通员工0
if(strategy.getPriority() > auditStrategy.getPriority()){
auditStrategy = strategy;
}
}
}
}
if(auditStrategy == null){
throw new RuntimeException("没有匹配到请假审核规则");
}else{
return auditStrategy;
}
}
}
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:40:03
* @description 策略工厂上下文
*/
public class LeaveServiceNew {
public void audit(LeaveForm leaveForm){
AuditStrategyFactory factory = AuditStrategyFactory.getInstance();
//返回符合条件的策略
AuditStrategy strategy = factory.getAuditStrategy(leaveForm);
//通过策略类进行审核
strategy.audit(leaveForm);
}
}
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:33:53
* @description 员工类
*/
public class Employee {
private String name; // 姓名
private Integer levle; // 级别
public Employee(String name,Integer levle){
this.name = name;
this.levle = levle;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getLevle() {
return levle;
}
public void setLevle(Integer levle) {
this.levle = levle;
}
}
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:34:29
* @description 请假实体
*/
public class LeaveForm {
private Employee employee;//员工对象
private String reason;//请假原因
private int days;//天数
private int type; //类型 0-病假 1-婚丧假 2-年假
public LeaveForm(Employee employee,String reason,int days,int type){
this.employee = employee;
this.reason = reason;
this.days = days;
this.type = type;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public int getDays() {
return days;
}
public void setDays(int days) {
this.days = days;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
package main.java.cn.test.strategy.V2;
/**
* @author ningzhaosheng
* @date 2023/6/11 14:40:26
* @description 测试类
*/
public class Client {
public static void main(String[] args) {
LeaveServiceNew leaveServiceNew = new LeaveServiceNew();
LeaveForm form1 = new LeaveForm(new Employee("李总经理", 9), "甲流发烧", 10, 0);
leaveServiceNew.audit(form1);
LeaveForm form2 = new LeaveForm(new Employee("打工人1", 2), "甲流发烧", 2, 0);
leaveServiceNew.audit(form2);
LeaveForm form3 = new LeaveForm(new Employee("打工人2", 3), "结婚", 2, 1);
leaveServiceNew.audit(form3);
LeaveForm form4 = new LeaveForm(new Employee("打工人3", 4), "请年假,休息休息", 5, 2);
leaveServiceNew.audit(form4);
}
}
执行结果:
经过上面的改造,我们已经消除了if-else的结构,每当新来了一种请假规则,只需要添加新的规则处理策略,并修改Factory中的集合。如果要使得程序符合开闭原则,则需要调整Factory中处理策略的获取方式,通过反射的方式,获取指定包下的所有Strategy实现类,然后放到字典集合中去.