一、簡述
日常開發中,會遇見類似於使用不同方式發送消息,例如:郵件、短信。再或者碰見文章分享之類的需求。那麼我們平時如果不是用設計模式來做的情況下,會出現很多個 if-else 或者 switch 語句塊。這樣的話,代碼耦合性也會非常高,將來再增加一個需求,則會導致一直增加判斷語句塊。也違反了面向對象的開閉原則。那麼我們有什麼好的解決方式呢?今次,則用反射+策略模式來重構一下代碼,使之更加靈活。
如果有代碼更好的優化方式,請下方留言。
碼雲:Demo地址
二、不使用反射的策略模式
抽象策略角色(接口)
public interface MyStragtegy {
String play();
}
具體實現策略
CatStragtegy實現CatStragtegy接口
public class CatStragtegy implements MyStragtegy {
@Override
public String play() {
String str = "貓玩毛線球,玩的一團糟";
return str;
}
}
DogStragtegy實現CatStragtegy接口
public class DogStragtegy implements MyStragtegy {
@Override
public String play() {
String str = "狗狗玩飛盤,玩的很開心";
return str;
}
}
環境角色(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
業務邏輯代碼
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
業務邏輯代碼
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 "還沒有這個寵物喲!~";
}
}
}
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反射實現策略模式,簡化了代碼,也讓開發人員更專注的寫業務代碼了,這樣如果我們增加了一個其他寵物的情況下,也只需要增加一個實現類就可以了。
點亮 ,告訴大家你也在看