实用设计模式实战:工厂+策略(另一种实现)

本节主要的知识点InitializingBean接口和DependsOn注解

书接上回,我们要用设计模式改造这个if/else

  public static void main(String[] args){
    String type = "common";
    operateByType(type);
  }

  private static void operateByType(String type) {
    if ("common".equals(type)){
      System.out.println("先查询缓存,缓存没有在查询数据库,同时更新缓存");
    }
    if ("update".equals(type)){
      System.out.println("直接更新缓存");
    }
  }

上回我们使用ApplicationContextAware接口,实现了一个工厂+策略模式。这回我们换一种方式使用spring bean的 InitializingBean 接口重写afterPropertiesSet方法来实现工厂 +策略模式。

InitializingBean 是 Spring 框架中的一个接口,用于在 Spring Bean 初始化时执行自定义的初始化逻辑。当一个 Spring Bean 实现了 InitializingBean 接口,它必须实现接口中的 afterPropertiesSet 方法。这个方法会在 Bean 的属性设置完成后(也就是依赖注入完成后),在 Bean 被容器初始化之后被调用。

定义一个接口

public interface AttributeNumberService {
    void operateByType();
}

定义一个工厂类


public class AttributeNumberFactory {

    private static final Map<String, AttributeNumberService> processServiceMap = new ConcurrentHashMap<>();

    public static AttributeNumberService get(String type) {
        Assert.notNull(type, "type can't be null");
        return processServiceMap.get(type);
    }

    public static void put(String type,AttributeNumberService attributeNumberService){
        Assert.notNull(type, "transCode can't be null");
        processServiceMap.put(type, attributeNumberService);
    }
}

定义一个SpringBeanUtil,从spring上下文获取bean


@Component
public class SpringBeanUtil implements ApplicationContextAware {

  private static ApplicationContext context;

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    SpringBeanUtil.context = applicationContext;
  }

  /** 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型. */
  public static <T> T getBean(Class<T> clazz) {
    return context.getBean(clazz);
  }
}

ApplicationContextAware 接口是 Spring 框架中的一个接口,用于实现对 Spring 应用上下文(ApplicationContext)的感知,从而使一个类能够获取对应用上下文的引用。通过实现这个接口,类可以访问 Spring 容器中的 bean 实例和其他 Spring 特性。
这个接口定义了一个方法 setApplicationContext,需要在实现类中实现。当 Spring 容器初始化 bean 时,如果 bean 实现了 ApplicationContextAware 接口,容器会自动调用 setApplicationContext 方法,并将应用上下文的引用作为参数传递给这个方法。

AttributeNumberService实现类CommonAttributeNumberServiceImpl

@Service
@DependsOn(value = {"springBeanUtil"})
public class CommonAttributeNumberServiceImpl implements AttributeNumberService,InitializingBean{
  @Override
  public void operateByType() {
    System.out.println("先查询缓存,缓存没有在查询数据库,同时更新缓存");
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    AttributeNumberFactory.put("common", SpringBeanUtil.getBean(CommonAttributeNumberServiceImpl.class));
  }
}

这里我们实现了InitializingBean的afterPropertiesSet方法目的是把CommonAttributeNumberServiceImpl实例放入工厂中,我们使用SpringBeanUtil获取CommonAttributeNumberServiceImpl的实例放入工厂。
使用DependsOn注解是因为springBeanUtil要先加载我们才能使用springBeanUtil工具类

@DependsOn 注解是 Spring 框架中的一个注解,用于指定 bean 之间的初始化顺序。通过使用 @DependsOn 注解,您可以明确指定一个 bean 依赖于其他 bean,以确保在容器初始化时,依赖的 bean 先于当前 bean 初始化

@Service
@DependsOn(value = {"springBeanUtil"})
public class UpdateAttributeNumberServiceImpl implements AttributeNumberService, InitializingBean {
  @Override
  public void operateByType() {
    System.out.println("直接更新缓存");
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    AttributeNumberFactory.put(
        "update", SpringBeanUtil.getBean(UpdateAttributeNumberServiceImpl.class));
  }
}

然后就可以使用啦

@SpringBootTest()
class ShejimoshiGcApplicationTests {


  @Test
  void operateByTypeTest() {
    AttributeNumberService common = AttributeNumberFactory.get("common");
    common.operateByType();
  }
}

我们发现这个方法比上次的方法更复杂些,所以在工作中我们还是用上次的方法比较好

你可能感兴趣的:(设计模式,设计模式)