【精选】如何在SpringBoot中优雅的使用抽象工厂 您所在的位置:网站首页 spring中实现ioc模式的方法 【精选】如何在SpringBoot中优雅的使用抽象工厂

【精选】如何在SpringBoot中优雅的使用抽象工厂

2023-11-22 12:11| 来源: 网络整理| 查看: 265

目录

前言 

一、没用spring之前,一般我的工厂类是这么实现的 。

1.这样实现可以不可以?

2.有什么缺点?

二、如何使用SpringBoot如何改造?

1.为了方便后期增加新的handler,先定义一个Person枚举。

2.PeronHandler接口

3.headMasterHandler实现类 ,@Compont 需要加上让spring管理 

4.teacherHandler实现类,@Compont 需要加上让spring管理 

 5. PersonHandlerFactory工厂

 6.测试

总结

前言 

对于程序员来说,23种设计模式最常用的估计就是工厂模式,不管是简单工厂还是抽象工厂。例如:在日常的业务编码handler类必不可少,为了易维护,好扩展,方便管理等。一般都会用抽象工厂对同一组handler进行统一封装。

一、没用spring之前,一般我的工厂类是这么实现的 。 public class Factory { /** * Object 就是抽象出来的父接口 */ private static final Map MAP = new HashMap(); /** * 通过静态代码块来填充MAP */ static { } public static Object getHandle(Integer code){ return MAP.get(code); } } 1.这样实现可以不可以?

        肯定是可以的。用的时候只要用调用静态方法就行。

2.有什么缺点? 一般这么做,具体的handler都不会给spring管理。有可能我们的handler要用到spring管理的类。这种情况下就需要借助工具类。现在的java程序员,大半都可以叫spring工程师。既然我们用了spring这么写就违背了IOC思想。如果我们需要新增handler,需要改动工厂类。在static代码块中增加新增的handler。 二、如何使用SpringBoot如何改造?

我们先假设,我们需要为学校里不同职位的人写处理器,先抽出顶层接口PersonHandler,具体实现类先假设有两个

HeadMasterHandler(校长处理器)TeacherHandler (老师处理器) 1.为了方便后期增加新的handler,先定义一个Person枚举。 package com.dreamland.springstudy.enums; import lombok.Getter; import lombok.ToString; /** * @author zhangyifeng * @date 2021-10-16 16:52 */ @Getter @ToString public enum PersonEnum { /** * 老师 */ TEACHER(10), /** * 校长 */ HEADMASTER(20), private final int code; PersonEnum(int code) { this.code = code; } } 2.PeronHandler接口 package com.dreamland.springstudy.handler; import com.dreamland.springstudy.enums.PersonEnum; /** * @author zhangyifeng * @date 2021-10-16 16:50 */ public interface PersonHandler { /** * 枚举 * @return {@link PersonEnum} */ PersonEnum getPersonEnum(); /** * * 具体的校验逻辑,由子类实现 * 一般都会携带入参,根据具体的业务需求定义。 * 这里主要是为了让spring管理,所以不带入参。 * * * @return true or false */ boolean handle(); } 3.headMasterHandler实现类 ,@Compont 需要加上让spring管理  package com.dreamland.springstudy.handler.impl; import com.dreamland.springstudy.enums.PersonEnum; import com.dreamland.springstudy.handler.PersonHandler; import org.springframework.stereotype.Component; /** * @author zhangyifeng * @date 2021-10-16 16:59 */ @Component public class HeadmasterHandler implements PersonHandler { @Override public PersonEnum getPersonEnum() { return PersonEnum.HEADMASTER; } @Override public boolean handle() { System.out.println("校长校验器工作~~~~"); // 写自己的校验逻辑 return true; } } 4.teacherHandler实现类,@Compont 需要加上让spring管理  package com.dreamland.springstudy.handler.impl; import com.dreamland.springstudy.enums.PersonEnum; import com.dreamland.springstudy.handler.PersonHandler; import org.springframework.stereotype.Component; /** * @author zhangyifeng * @date 2021-10-16 16:58 */ @Component public class TeacherHandler implements PersonHandler { @Override public PersonEnum getPersonEnum() { return PersonEnum.TEACHER; } @Override public boolean handle() { System.out.println("老师校验器工作~~~~"); // 写自己的校验逻辑 return true; } }  5. PersonHandlerFactory工厂,@Compont 需要加上让spring管理 

最重要的工厂类如下 有两个重要的接口需要实现,有两个重要的方法

InitializingBean  接口中 afterPropertiesSet()   作用:用于初始化替代 静态代码块ApplicationContetAware 接口中 setApplicationContext(ApplicationContext var1) 作用:获取ApplicationContext对象

这两个接口中的方法就是关键,想知道这两个接口中方法的作用,有兴趣的可用去看下源码,官方的解释更好。

package com.dreamland.springstudy.handler; import lombok.NonNull; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; /** * @author zhangyifeng * @date 2021-10-16 17:03 */ @Component public class PersonHandlerFactory implements InitializingBean, ApplicationContextAware { private static final Map MAP = new HashMap(); private ApplicationContext applicationContext; public PersonHandler createHandler(Integer personCode) { Supplier p = MAP.get(personCode); if (p != null) { return p.get(); } throw new IllegalArgumentException("No such PersonHandler by code:" + personCode); } @Override public void afterPropertiesSet() throws Exception { applicationContext.getBeansOfType(PersonHandler.class) .values() .forEach(c -> MAP.put(c.getPersonEnum().getCode(), () -> c)); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }  6.测试

检验是否可用通过工厂拿到具体的handler,我写个接口测试,方便一点: 

package com.dreamland.springstudy.Controller; import com.dreamland.springstudy.handler.PersonHandler; import com.dreamland.springstudy.handler.PersonHandlerFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * @author zhangyifeng * @date 2021-10-16 17:25 */ @RestController @Slf4j public class TestController { @Autowired PersonHandlerFactory personHandlerFactory; @GetMapping("/handler") public void testHandler(@RequestParam("code")Integer code){ log.info("/handler code:{}",code); PersonHandler handler = personHandlerFactory.createHandler(code); handler.handle(); } }

 测试结果证明可用从工厂类中拿到不同的handler:

总结 这么实现很好扩展,例如我们在加一个学生处理器(studentHandler),只要写2步,就可以使用了。 枚举中增加相关定义实现父接口具体handler是给spring管理的,非常方面我们用srping管理的其他类



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有