Spring反射+策略模式Demo


一、簡述

日常開發中,會遇見類似於使用不同方式發送消息,例如:郵件、短信。再或者碰見文章分享之類的需求。那麼我們平時如果不是用設計模式來做的情況下,會出現很多個 if-else 或者 switch 語句塊。這樣的話,代碼耦合性也會非常高,將來再增加一個需求,則會導致一直增加判斷語句塊。也違反了面向對象的開閉原則。那麼我們有什麼好的解決方式呢?今次,則用反射+策略模式來重構一下代碼,使之更加靈活。

如果有代碼更好的優化方式,請下方留言。

碼雲:Demo地址

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

抽象策略角色(接口)

public interface MyStragtegy {
String play();
}
  • 1

  • 2

  • 3

具體實現策略

CatStragtegy實現CatStragtegy接口

public class CatStragtegy implements MyStragtegy {
@Override
public String play() {
String str = "貓玩毛線球,玩的一團糟";
return str;
}
}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

DogStragtegy實現CatStragtegy接口

public class DogStragtegy implements MyStragtegy {
@Override
public String play() {
String str = "狗狗玩飛盤,玩的很開心";
return str;
}
}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

環境角色(Content)

public class MyStragtrgyContent  {

private String type;//策略方式

private MyStragtegy myStragtegy;//策略接口

public MyStragtrgyContent(String type, MyStragtegy myStragtegy) {
this.type = type;
this.myStragtegy = myStragtegy;
}

public MyStragtegy getMyStragtegy() {
return myStragtegy;
}

public boolean option(String type){
return this.type.equals(type);
}

}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

業務邏輯代碼

  1. service代碼

@Component
public class StragtegyService {

private static List<MyStragtrgyContent> stragtegies = new ArrayList<>();

static {
stragtegies.add(new MyStragtrgyContent("cat",new CatStragtegy()));
stragtegies.add(new MyStragtrgyContent("dog",new DogStragtegy()));
}

public String play(String type){
List<MyStragtrgyContent> collect = stragtegies.stream().filter(x -> x.option(type)).collect(Collectors.toList());
if (collect!=null&&collect.size()>0){
return collect.get(0).getMyStragtegy().play();
}else {
return "我們還沒有這個寵物喲!~";
}
}
}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

2.Controller代碼

@Controller
public class DemoController {

@Autowired
private StragtegyService stragtegyService;

@ResponseBody
@RequestMapping("play")
public String play(String type){
if (type!=null&&!"".equals(type)){
return stragtegyService.play(type);
}else {
return "要選擇一起玩的寵物喲!~";
}
}
}
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

總結

代碼耦合性太高,每加一個寵物則需要再service中的靜態代碼塊添加實例從而導致,我們如果忘記加了,則實現不了新寵物的陪玩。也違反了類的開閉原則。

接下來修改代碼用spring反射機制實現

三、使用Spring反射機制實現策略模式

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

public interface MyStragtegy {
String play();
}

修改具體實現策略(交給spring管理,起別名是爲了方便取)**

@Component("cat")//如果用反射機制的情況下需要交給spring管理
public class CatStragtegy implements MyStragtegy {
@Override
public String play() {
String str = "貓玩毛線球,玩的一團糟";
return str;
}
}
@Component("dog")//如果用反射機制的情況下需要交給spring管理
public class DogStragtegy implements MyStragtegy {
@Override
public String play() {
String str = "狗狗玩飛盤,玩的很開心";
return str;
}
}

修改環境角色(上下文)

@Component
public class MyStragtrgyReflexContent implements ApplicationContextAware,InitializingBean {

private Map<String,MyStragtegy> beanMap ;

private ApplicationContext applicationContext;


/**
* 實現ApplicationContextAware接口,Spring容器會在創建MyStragtrgyReflexContent類之後,
* 自動調用實現接口的setApplicationContextAware()方法,
* 調用該方法時,會將ApplicationContext(容器本身)作爲參數傳給該方法,
* 我們可以在該方法中將Spring傳入的參數ApplicationContext賦給MyStragtrgyReflexContent對象的applicationContext實例變量,因此接下來可以通過該applicationContext實例變量來訪問容器本身。
*
* 作者:那我懂你意思了_de16
* 鏈接:https://www.jianshu.com/p/e435dd6c7339
* 來源:簡書
* 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
* @param applicationContext
* @throws BeansException
*/

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

/**
* 實現InitializingBean接口,該接口提供了afterPropertiesSet方法。
* spirng容器在初始化bean的時候會執行afterPropertiesSet方法,
* 我們可以在該方法中調用applicationContext接口提供的getBeansOfType方法獲得實現MyStragtegy類的Bean,將之存儲至map集合中
*
* 作者:那我懂你意思了_de16
* 鏈接:https://www.jianshu.com/p/e435dd6c7339
* 來源:簡書
* 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
* @throws Exception
*/

@Override
public void afterPropertiesSet() throws Exception {
Map<String,MyStragtegy> map = applicationContext.getBeansOfType(MyStragtegy.class);
this.beanMap = map;
}

public MyStragtegy getMyStragtegy(String beanName){
return this.beanMap.get(beanName);
}



}
  • MyStragtrgyReflexContent 類實現ApplicationContextAware接口,Spring容器會在創建MyStragtrgyReflexContent 類之後,自動調用實現接口的setApplicationContextAware()方法,調用該方法時,會將ApplicationContext(容器本身)作爲參數傳給該方法,我們可以在該方法中將Spring傳入的參數ApplicationContext賦給MyStragtrgyReflexContent 對象的applicationContext實例變量,因此接下來可以通過該applicationContext實例變量來訪問容器本身。

  • 實現InitializingBean接口,該接口提供了afterPropertiesSet方法。spirng容器在初始化bean的時候會執行afterPropertiesSet方法,我們可以在該方法中調用applicationContext接口提供的getBeansOfType方法獲得實現MyStragtegy類的Bean,將之存儲至map集合中。

  • 摘錄自https://www.jianshu.com/p/e435dd6c7339

業務邏輯代碼

  1. Service代碼

這裏的type就作爲BeanName直接傳過去了,如果不想這麼做也可以自己轉換下

@Service
public class StragtegyReflexService {

@Autowired
private MyStragtrgyReflexContent reflexContent;


public String play(String type){
MyStragtegy myStragtegy = reflexContent.getMyStragtegy(type);
if (myStragtegy!=null){
return myStragtegy.play();
}else {
return "還沒有這個寵物喲!~";
}
}

}
  1. Controller

@Controller
public class DemoController {

@Autowired
private StragtegyService stragtegyService;

@ResponseBody
@RequestMapping("play")
public String play(String type){
if (type!=null&&!"".equals(type)){
return stragtegyService.play(type);
}else {
return "要選擇一起玩的寵物喲!~";
}
}

@ResponseBody
@RequestMapping("playReflex")
public String playReflex(String type){
if (type!=null&&!"".equals(type)){
return stragtegyService.play(type);
}else {
return "要選擇一起玩的寵物喲!~";
}
}

}

總結

通過使用spring反射實現策略模式,簡化了代碼,也讓開發人員更專注的寫業務代碼了,這樣如果我們增加了一個其他寵物的情況下,也只需要增加一個實現類就可以了。

阿里面試官:HashMap中的8和6的關係(1)

各大互聯網企業Java面試題彙總,如何成功拿到百度的offer

阿里面試題剖析,如何保證消息不被重複消費?

一文搞定併發面試題

深入理解JVM垃圾收集機制,下次面試你準備好了嗎







交流/資源分享

OMG關注它



點亮 ,告訴大家你也在看 



本文分享自微信公衆號 - Java高級架構師(java968)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章