以下代码可通过以下链接获得。
我的源码链接
策略模式指的是对于同样的一件事情,根据不同的场景给出不同的策略来解决同一件事情。比较好理解的一个例子就是,我们定义一个打招呼事件,每个人都可以实现打招呼这么一个事件。这样我们就定义一个打招呼的接口,然而不同国家的人,对打招呼有不同的实现。例如一个中国人,打招呼的时候说“你好!”,一个美国人打招呼的时候说“hello!”,一个日本人打招呼说“こんにちは“。假设我们写的是一个景区的道路指引系统的欢迎页,那么对于选择了不同语言的游客,要给出不同的招呼语。这就是一个简单的策略模式。
获取策略时,我们使用简单的工厂模式来实现。根据输入的语言,来获取对应的策略实例。废话不多说,上代码。
首先我们创建一个打招呼的接口,我们定义为GreetService。代码如下
public interface GreetService {
// 打招呼方法,参数为用户名称
String sayHello(String name);
}
接口里面有一个打招呼方法,然后创建三个实现类,分别是中国人,美国人和日本人。
代码如下
中国人实现类
public class ChinaGreetServiceImpl implements GreetService {
public String sayHello(String name) {
return "你好!" + name;
}
}
美国人实现类
public class UsaGreetServiceImpl implements GreetService {
public String sayHello(String name) {
return "Hello !" + name;
}
}
日本人实现类
public class JapanGreetServiceImpl implements GreetService {
public String sayHello(String name) {
return "こんにちは!" + name;
}
}
然后我们创建一个Context对象,用来记录选用的策略,以及执行策略方法。
public class GreetStrategyContext {
// 记录策略
private GreetService greetService;
// 选用的语言
private String language;
public void selectGreetStrategy(GreetService greetService){
this.greetService = greetService;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String handel(String name){
return this.greetService.sayHello(name);
}
}
然后创建一个工厂类,用来获取策略实例。
public class GreetStrategyFactory {
/**
* 自动注入所有的策略实例
*/
@Autowired
private Map<String, GreetService> greetServiceMap;
/**
* 根据语言返回对应的策略实例
*
* @param context
* @return
*/
public GreetService getGreetStrategyByLanguage(GreetStrategyContext context){
return greetServiceMap.get(context.getLanguage());
}
}
如果是在spring项目中,可以在上面的对象上使用注解,让spring容器可以扫描到,并加载这些对象。这里我们采用简单的手动查找方式,可以不用启动整个Spring容器。
首先需要创建实例,我们通过最常用的xml方式,创建实例。代码如下
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="chinese" class="org.designMode.demo.strategyMode.Strategies.ChinaGreetServiceImpl"/>
<bean id="japanese" class="org.designMode.demo.strategyMode.Strategies.JapanGreetServiceImpl"/>
<bean id="english" class="org.designMode.demo.strategyMode.Strategies.UsaGreetServiceImpl"/>
<bean id="greetStrategyContext" class="org.designMode.demo.strategyMode.GreetStrategyContext"/>
<bean id="greetStrategyFactory" class="org.designMode.demo.strategyMode.GreetStrategyFactory"/>
beans>
下面,我们来创建Demo对象
public class SayHelloDemo {
@Resource
private GreetStrategyFactory greetStrategyFactory;
public static void main(String[] args) {
// 创建上下文
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 创建一个 definitionReader 对象
XmlBeanDefinitionReader definitionReader = new XmlBeanDefinitionReader(applicationContext);
// 定义 xml 配置文件相对路径
String xmlResourcePath = "META-INFO/strategy-mode-context.xml";
// 加载
definitionReader.loadBeanDefinitions(xmlResourcePath);
// 启动上下文
applicationContext.refresh();
// 获取策略context
GreetStrategyContext greetStrategyContext = (GreetStrategyContext)applicationContext.getBean("greetStrategyContext");
// 获取一个工厂类
GreetStrategyFactory greetStrategyFactory = (GreetStrategyFactory)applicationContext.getBean("greetStrategyFactory");
// 设置策略使用的是英语 English
greetStrategyContext.setLanguage("english");
// 工厂方法获取策略实例
GreetService greetService = greetStrategyFactory.getGreetStrategyByLanguage(greetStrategyContext);
// 注入策略实例
greetStrategyContext.selectGreetStrategy(greetService);
// 执行策略方法
String helloWord = greetStrategyContext.handel("jeff");
// 打印结果
System.out.println(helloWord);
// 关闭上下文
applicationContext.close();
}
}
运行结果
org.designMode.demo.strategyMode.SayHelloDemo
Hello !jeff
Process finished with exit code 0
同样的,我们把使用的语言改成中文和日语,再试一次可得到对应的结果。
这就是一个简单的策略方法实例。
在工厂方法里面,使用了@Autowired方法的特殊用法,集合注入。
/**
* 自动注入所有的策略实例
*/
@Autowired
private Map<String, GreetService> greetServiceMap;
这里spring容器会自动注入所有的GreetService接口的实现类,并把实例对象的名称放在map的key中,实例对象放在map的value中。这里的名称,即是xml文件中指定的id属性。换成name属性,也可以放到map的key中。spring的另一个注解@Resource也有同样的用法。
使用name也一样可以实现。
除此之外,集合注入还可以用List来承载。这样的注入,只会把所有的实现类放在list中,不会记录实现类的名称。
spring容器是怎么实现这个功能的呢?实际上是通过spring Ioc的依赖注入,按照类型注入的方式来实现的。因此,可以不使用@Autowird或者@Resource注解,通过xml配置,手动配置依赖注入,也是可以实现的。
这里也提供两种方式
<bean name="greetStrategyFactory" class="org.designMode.demo.strategyMode.GreetStrategyFactory" autowire="byType"/>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<bean name="chinese" class="org.designMode.demo.strategyMode.Strategies.ChinaGreetServiceImpl"/>
<bean name="japanese" class="org.designMode.demo.strategyMode.Strategies.JapanGreetServiceImpl"/>
<bean name="english" class="org.designMode.demo.strategyMode.Strategies.UsaGreetServiceImpl"/>
<bean name="greetStrategyContext" class="org.designMode.demo.strategyMode.GreetStrategyContext"/>
<bean name="greetStrategyFactory" class="org.designMode.demo.strategyMode.GreetStrategyFactory">
<property name="greetServiceMap">
<util:map>
<entry key="chinese" value-ref="chinese"/>
<entry key="japanese" value-ref="japanese"/>
<entry key="english" value-ref="english"/>
util:map>
property>
bean>
beans>
通过以上两个种方式,手动配置,并使用依赖注入的setter方法注入。以上两种方式只是提供一个思考的思路,实际开发中,推荐使用@Autowired注解和@Resource注解。Spring官方也推荐使用这两个注解。
以上就是这篇博文的全部内容,如有不正,还望各位大佬指出。