设计模式(二)--策略模式实践--基于@Autowired注解实现(Autowired集合注入)

以下代码可通过以下链接获得。
我的源码链接

什么是策略模式

策略模式指的是对于同样的一件事情,根据不同的场景给出不同的策略来解决同一件事情。比较好理解的一个例子就是,我们定义一个打招呼事件,每个人都可以实现打招呼这么一个事件。这样我们就定义一个打招呼的接口,然而不同国家的人,对打招呼有不同的实现。例如一个中国人,打招呼的时候说“你好!”,一个美国人打招呼的时候说“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方式,创建实例。代码如下

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- 打招呼实现类,id使用语言名称,方便查找 -->
    <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"/>

    <!-- 创建Context实例 -->
    <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配置,手动配置依赖注入,也是可以实现的。
这里也提供两种方式

  • 直接使用autowire属性
    并设置为按类型注入
<!-- 创建策略工厂 -->
    <bean name="greetStrategyFactory" class="org.designMode.demo.strategyMode.GreetStrategyFactory" autowire="byType"/>
  • 使用插件
    使用xml文件配置的util插件,具体可以参照Spring官方文档。
    配置代码如下
<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">

    <!-- 打招呼实现类,id使用语言名称,方便查找 -->
    <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"/>

    <!-- 创建Context实例 -->
    <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官方也推荐使用这两个注解。

以上就是这篇博文的全部内容,如有不正,还望各位大佬指出。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值