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);
}
}