JAVA设计模式-策略模式及在Springboot2.X中写法

JAVA设计模式-策略模式及在Springboot2.X中写法

策略模式的定义 :策略模式是一种行为型设计模式,定义了一系列算法,并将每个算法封装起来,使它们可以互相替换
策略模式 :在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。

何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。

如何解决:将这些算法封装成一个一个的类,任意地替换。

关键代码:实现同一个接口。

应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。

策略模式三种角色:

  • 1、环境上下文(Context)角色:持有一个Strategy引用,委托策略变量调用具体策略所实现的策略接口中的方法。
  • 2、策略(Strategy)角色:抽象角色,通常由一个接口或抽象类实现,此角色给出所有的具体策略类所需接口。
  • 3、具体策略(ConcreteStrategy)角色:具体实现策略接口的类,包装了相关的算法或行为。

一、经典的策略模式写法

java 复制代码
/**
 * 策略接口
 */
public interface Strategy {
    int doOperation(int num1, int num2);
}


/**
 * 加法策略
 */
class OperationAdd implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }
}

/**
 * 减法策略
 */
class OperationSub implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 - num2;
    }
}


/**
 * 策略上下文类
 */
class Context {

    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int num1, int num2) {
        return strategy.doOperation(num1, num2);
    }
}


class Main{
    public static void main(String[] args){
        // 策略上下文
        Context context = new Context(new OperationAdd());
        // 加法策略
        System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
        // 减法策略
        context = new Context(new OperationSub());
        System.out.println("10 - 5 = " + context.executeStrategy(10, 5));

    }
}

但是上述的写法中,在具体使用过程中,要需要new具体的策略,而不能简单的传输一些字段来实现

二、Springboot2.X中策略模式写法

参考链接

在springboot中实现的时候可以采用@Component来标记为bean,通过获取bean来直接得到想要的具体策略

下述例子采用数据库存储的方式,将具体的code和beanId关联在一起,通过code-->获取beanId-->获取bean-->执行bean,从而不需要在Context中写if-else,或者在调用过程中写死new具体的策略

同理,使用 读取缓存、读取枚举、读取数据库等方式来实现,一定程度上解耦了抽象类和实体类之间的关联。

1.首先定义策略模式的策略接口

java 复制代码
public interface Strategy {
	int doOperation(int num1, int num2);
}

2.定义具体的策略

在springboot中可以使用@Component标记一个类为组件

实现加法策略

java 复制代码
@Component
public class OperationAdd implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }
}

实现减法策略

java 复制代码
@Component
class OperationSub implements Strategy {
    @Override
    public int doOperation(int num1, int num2) {
        return num1 - num2;
    }
}

3.实现环境上下文Context

java 复制代码
@Component
public class ContextStrategy {

    @Resource
    private OperatorMapper operatorMapper;

    public int executeStrategy(int code,int num1, int num2) {
    	OperatorEntity entity = OperatorMapper.getOperator(code);
    	Strategy strategy = SpringUtils.getBean(entity.getStrategyBeanId(),Strategy.class);
        return strategy.doOperation(num1, num2);
    }
}

4.使用

java 复制代码
@RestController
public class OperatorController {
    @Autowired
    private ContextStrategy contextStrategy;

    @GetMapping("/toDoOperator")
    public String toDoOperator(String code,int num1,int num2){
        return contextStrategy.doOperation(code,num1,num2);
    }
}

5.细节部分

注意:这里有个细节问题,数据库存储的beanId一定要跟我们定义的bean保持一致,否则根据beanId去spring容器中获取实例对象会失败!

附根据beanId获取对应实例对象的utils

java 复制代码
/**
 * 根据beanId 从spring容器中获取对象
 */
@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }

}
相关推荐
CQU_JIAKE1 小时前
11.7[高体】
java·后端·spring
apcipot_rain2 小时前
C++转Java日记(04)
java·开发语言·c++
特立独行的猫A2 小时前
我给女儿写了个打字练习:一边敲键盘,一边把小学英语单词记牢
java·后端·python
憧憬成为java架构高手的小白4 小时前
LangGraph4j 实战(下)
java
天诰4 小时前
SA-K-11 检索会消失吗与四个未解问题
java·服务器·人工智能·python·机器学习·ai编程
这个昵称不容易8 小时前
SpringBoot「衣依」服装销售平台:144个Java文件180个接口,从挑衣服到收货评价整条链路都在
java·springboot·毕设
计算机毕设定制辅导-无忧学长8 小时前
《基于微信小程序的居家医疗陪护预约系统设计与实现》
java·spring boot·微信小程序·uniapp·居家医疗陪护预约系统
文丑颜不良啊10 小时前
LeetCode2221~2240题目解析
java·leetcode
秋饼10 小时前
Computer Use Agent Java 落地实战:感知-行动循环、执行器与安全围栏生产级实现
java·ai·技术分享·后端开发
心若自由何处是束缚12 小时前
适配器模式:从原理到实战的完整指南
设计模式·适配器模式