KNOW

Spring反射+策略模式Demo

2021-01-04  本文已影响0人  程序员木子

一、简述

日常开发中,会遇见类似于使用不同方式发送消息,例如:邮件、短信。再或者碰见文章分享之类的需求。那么我们平时如果不是用设计模式来做的情况下,会出现很多个 if-else 或者 switch 语句块。这样的话,代码耦合性也会非常高,将来再增加一个需求,则会导致一直增加判断语句块。也违反了面向对象的开闭原则。那么我们有什么好的解决方式呢?今次,则用反射+策略模式来重构一下代码,使之更加灵活。

二、不使用反射的策略模式

抽象策略角色(接口)

publicinterfaceMyStragtegy{

Stringplay();

}

具体实现策略

CatStragtegy实现CatStragtegy接口

publicclassCatStragtegyimplementsMyStragtegy{

@Override

publicStringplay(){

String str="猫玩毛线球,玩的一团糟";

returnstr;

}

}

DogStragtegy实现atStragtegy接口

publicclassDogStragtegyimplementsMyStragtegy{

@Override

publicStringplay(){

String str="狗狗玩飞盘,玩的很开心";

returnstr;

}

}

环境角色(Content)

publicclassMyStragtrgyContent{

privateString type;//策略方式

privateMyStragtegy myStragtegy;//策略接口

publicMyStragtrgyContent(String type,MyStragtegy myStragtegy){

this.type=type;

this.myStragtegy=myStragtegy;

}

publicMyStragtegygetMyStragtegy(){

returnmyStragtegy;

}

publicbooleanoption(String type){

returnthis.type.equals(type);

}

}

业务逻辑代码

1.service代码

@Component

publicclassStragtegyService{

privatestaticList<MyStragtrgyContent>stragtegies=newArrayList<>();

static{

stragtegies.add(newMyStragtrgyContent("cat",newCatStragtegy()));

stragtegies.add(newMyStragtrgyContent("dog",newDogStragtegy()));

}

publicStringplay(String type){

List<MyStragtrgyContent>collect=stragtegies.stream().filter(x->x.option(type)).collect(Collectors.toList());

if(collect!=null&&collect.size()>0){

returncollect.get(0).getMyStragtegy().play();

}else{

return"我们还没有这个宠物哟!~";

}

}

}

2.Controller代码

@Controller

publicclassDemoController{

@Autowired

privateStragtegyService stragtegyService;

@ResponseBody

@RequestMapping("play")

publicStringplay(String type){

if(type!=null&&!"".equals(type)){

returnstragtegyService.play(type);

}else{

return"要选择一起玩的宠物哟!~";

}

}

代码耦合性太高,每加一个宠物则需要再service中的静态代码块添加实例从而导致,我们如果忘记加了,则实现不了新宠物的陪玩。也违反了类的开闭原则。

接下来修改代码用spring反射机制实现

三、使用Spring反射机制实现策略模式

接口不做修改,使用原来的接口(策略角色)

publicinterfaceMyStragtegy{

Stringplay();

}

修改具体实现策略(交给spring管理,起别名是为了方便取)**

@Component("cat")//如果用反射机制的情况下需要交给spring管理

publicclassCatStragtegyimplementsMyStragtegy{

@Override

publicStringplay(){

String str="猫玩毛线球,玩的一团糟";

returnstr;

}

}

@Component("dog")//如果用反射机制的情况下需要交给spring管理

publicclassDogStragtegyimplementsMyStragtegy{

@Override

publicStringplay(){

String str="狗狗玩飞盘,玩的很开心";

returnstr;

修改环境角色(上下文)

@Component

publicclassMyStragtrgyReflexContentimplementsApplicationContextAware,InitializingBean{

privateMap<String,MyStragtegy>beanMap;

privateApplicationContext applicationContext;

/**

* 实现ApplicationContextAware接口,Spring容器会在创建MyStragtrgyReflexContent类之后,

* 自动调用实现接口的setApplicationContextAware()方法,

* 调用该方法时,会将ApplicationContext(容器本身)作为参数传给该方法,

* 我们可以在该方法中将Spring传入的参数ApplicationContext赋给MyStragtrgyReflexContent对象的applicationContext实例变量,因此接下来可以通过该applicationContext实例变量来访问容器本身。

@Override

publicvoidsetApplicationContext(ApplicationContext applicationContext)throwsBeansException{

this.applicationContext=applicationContext;

}

/**

* 实现InitializingBean接口,该接口提供了afterPropertiesSet方法。

* spirng容器在初始化bean的时候会执行afterPropertiesSet方法,

* 我们可以在该方法中调用applicationContext接口提供的getBeansOfType方法获得实现MyStragtegy类的Bean,将之存储至map集合中

@Override

publicvoidafterPropertiesSet()throwsException{

Map<String,MyStragtegy>map=applicationContext.getBeansOfType(MyStragtegy.class);

this.beanMap=map;

}

publicMyStragtegygetMyStragtegy(String beanName){

returnthis.beanMap.get(beanName);

}

}

实现InitializingBean接口,该接口提供了afterPropertiesSet方法。spirng容器在初始化bean的时候会执行afterPropertiesSet方法,我们可以在该方法中调用applicationContext接口提供的getBeansOfType方法获得实现MyStragtegy类的Bean,将之存储至map集合中。

业务逻辑代码

1.Service代码

这里的type就作为BeanName直接传过去了,如果不想这么做也可以自己转换下

2.Controller

总结

通过使用spring反射实现策略模式,简化了代码,也让开发人员更专注的写业务代码了,这样如果我们增加了一个其他宠物的情况下,也只需要增加一个实现类就可以了。

上一篇 下一篇

猜你喜欢

热点阅读