策略模式及使用Spring實現策略模式+工廠模式及spring 源碼


策略模式及使用Spring實現策略模式+工廠模式

我們實現某個接口時,可能會有很多種不同的實現方式。這些不同的實現方式通過一定的規則可以隨意切換使用時,我們就可以考慮使用策略模式來實現。例如本文將要做的事情:打印TES與DWG進行BO5的所有結果。

一、定義
Define a family of algorithms,encapsulate each one, and make them interchangeable.

定義一組算法,將每個算法都封裝起來,並且使他們之間可以轉換。

二、UML類圖
圖片來自於《大話設計模式》

 

 

 

主要角色如下:

封裝角色(Context):也叫做上下文角色,起承上啟下封裝作用,屏蔽高層模塊對策略、算法的直接訪問,封裝可能存在的變化
抽象策略角色(Strategy):策略家族的抽象,通常為接口,定義每個策略或算法必須具有的方法和屬性
具體策略角色(ConcreteStrategy):實現抽象策略中的操作,該類含有具體的算法
2、實現策略模式
//抽象策略角色
public interface Strategy {
//策略模式的運算法則
void doSomething();
}
1
2
3
4
5
//具體策略角色
public class ConcreteStrategy1 implements Strategy {
@Override
public void doSomething() {
System.out.println("具體策略1的運算法則...");
}
}
1
2
3
4
5
6
7
//具體策略角色
public class ConcreteStrategy2 implements Strategy {
@Override
public void doSomething() {
System.out.println("具體策略2的運算法則...");
}
}
1
2
3
4
5
6
7
//封裝角色
public class Context {
//抽象策略
private Strategy strategy;

//構造函數設置具體策略
public Context(Strategy strategy) {
this.strategy = strategy;
}

//封裝后的策略方法
public void doAnything() {
this.strategy.doSomething();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Client {
public static void main(String[] args) {
//聲明一個具體的策略
Strategy strategy = new ConcreteStrategy1();
//聲明上下文對象
Context context = new Context(strategy);
//執行封裝后的方法
context.doAnything();
}
}
1
2
3
4
5
6
7
8
9
10
執行結果如下:

具體策略1的運算法則...
1
二、使用Spring實現策略模式+工廠模式
1、實現策略類
public interface Strategy {
//策略模式的運算法則
void doSomething();
}
1
2
3
4
@Component
public class ConcreteStrategy1 implements Strategy {
@Override
public void doSomething() {
System.out.println("具體策略1的運算法則...");
}

@Override
public String toString() {
return "具體策略1";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@Component
public class ConcreteStrategy2 implements Strategy {
@Override
public void doSomething() {
System.out.println("具體策略2的運算法則...");
}

@Override
public String toString() {
return "具體策略2";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@Component
public class DefaultStrategy implements Strategy {
@Override
public void doSomething() {
System.out.println("默認策略的運算法則...");
}

@Override
public String toString() {
return "默認策略";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2、實現工廠類
@Component
public class StrategyFactory {
//Spring會自動將Strategy接口的實現類注入到這個Map中,key為bean id,value值則為對應的策略實現類
@Autowired
private Map<String, Strategy> strategyMap;

public Strategy getBy(String strategyName) {
return strategyMap.get(strategyName);
}
}
1
2
3
4
5
6
7
8
9
10
Spring會自動將Strategy接口的實現類注入到這個Map中(前提是實現類得是交給Spring 容器管理的),這個Map的key為bean id,可以用@Component(value = "xxx")的方式設置,如果直接用默認的方式的話,就是首字母小寫。value值則為對應的策略實現類

 

測試類:

@SpringBootTest
class SpringbootDemoApplicationTests {

@Autowired
private ApplicationContext context;

@Test
public void test() {
context.getBean(StrategyFactory.class).getBy("concreteStrategy1").doSomething();
context.getBean(StrategyFactory.class).getBy("concreteStrategy2").doSomething();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
執行結果如下:

具體策略1的運算法則...
具體策略2的運算法則...
1
2
3、別名轉換
上面測試類調用的使用使用的bean id,實際業務中應該是將傳入的code轉義成對應的策略類的bean id

@Component
@PropertySource("classpath:application.properties")
@ConfigurationProperties(prefix = "strategy")
public class StrategyAliasConfig {
private HashMap<String, String> aliasMap;

public static final String DEFAULT_STATEGY_NAME = "defaultStrategy";

public HashMap<String, String> getAliasMap() {
return aliasMap;
}

public void setAliasMap(HashMap<String, String> aliasMap) {
this.aliasMap = aliasMap;
}

public String of(String entNum) {
return aliasMap.get(entNum);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
配置文件application.properties

strategy.aliasMap.strategy1=concreteStrategy1
strategy.aliasMap.strategy2=concreteStrategy2
1
2
@Component
public class StrategyFactory {
@Autowired
private StrategyAliasConfig strategyAliasConfig;

//Spring會自動將Strategy接口的實現類注入到這個Map中,key為bean id,value值則為對應的策略實現類
@Autowired
private Map<String, Strategy> strategyMap;

//找不到對應的策略類,使用默認的
public Strategy getBy(String strategyName) {
String name = strategyAliasConfig.of(strategyName);
if (name == null) {
return strategyMap.get(StrategyAliasConfig.DEFAULT_STATEGY_NAME);
}
Strategy strategy = strategyMap.get(name);
if (strategy == null) {
return strategyMap.get(StrategyAliasConfig.DEFAULT_STATEGY_NAME);
}
return strategy;

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
測試類:

@SpringBootTest
class SpringbootDemoApplicationTests {

@Autowired
private ApplicationContext context;

@Test
public void test() {
context.getBean(StrategyFactory.class).getBy("strategy1").doSomething();
context.getBean(StrategyFactory.class).getBy("strategy2").doSomething();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
執行結果如下:

具體策略1的運算法則...
具體策略2的運算法則...
1
2

 

特別注意,主要我遇到的坑有

1.spring 必須自己在unit test 中設置初始化

2. //該標簽 EnableConfigurationProperties 才會讓 configuration 注解生效,負責始終取不到配置文件內容,這個很重要

@EnableConfigurationProperties

測試截圖

 

 

 

我整理的代碼地址: https://github.com/Amos666/FactoryTest    

歡迎大家學習交流


參考:

《設計模式之禪》

https://mp.weixin.qq.com/s/cc4Slm0Ta22PShYuKpO2mQ
————————————————
版權聲明:本文為CSDN博主「邋遢的流浪劍客」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_40378034/article/details/104121363

 

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM