Spring反射+策略模式Demo

一、简述

日常开发中,会遇见类似于使用不同方式发送消息,例如:邮件、短信。再或者碰见文章分享之类的需求。那么我们平时如果不是用设计模式来做的情况下,会出现很多个 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. 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 "我们还没有这个宠物哟!~";
        }
    }
}

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 "要选择一起玩的宠物哟!~";
        }
    }
}

总结

代码耦合性太高,每加一个宠物则需要再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反射实现策略模式,简化了代码,也让开发人员更专注的写业务代码了,这样如果我们增加了一个其他宠物的情况下,也只需要增加一个实现类就可以了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值