欢迎来到代码驿站!

JAVA代码

当前位置:首页 > 软件编程 > JAVA代码

详解spring-boot下如何满足多生产环境中个性化定制功能

时间:2023-01-06 09:04:16|栏目:JAVA代码|点击:

在项目的开发中,我们很难做到开发一套标准的流程来解决所有客户的需求。比如,我们当前的计量项目,分别运行于赤峰市和河北省。虽然两个区域处理的业务相同,但是对细节的实现要求却不同。前面也学习过计量检定软件,其为了解决各个定制者使用的功能需求,最后采取的方案是:将基础项目复制多份,进而满足不同的客户需求。优点当然是有的,但比起缺点来,优点便不值一提。缺点很明显,总结为一句话就是:项目变得难以维护。所以,当前让我们看到的就是,几个开发人员,每天处于解决问题当中。本文将给出一种方案,来有效的规避上述问题。

资源与环境

示例代码:https://github.com/mengyunzhi/springBootSampleCode/tree/master/dynamic-autowire

开发环境:java1.8 + spring-boot:2.1.3.RELEASE

需求假设

  • 假设使用本项目的人员为:中国人、美国人,分别能接受的语言为中文和英文。
  • 项目运行后,可以根据当前的访问人员是国籍来动态显示:你好hello
  • 有新的需求后,比如:增加德国人并显示Hallo。增加功能时,不更改核心代码。
  • 不使用if else

注意:如果你看完需求假设后,毫无触动,请忽略本文以下内容

解决方案

解决方案中,我们涉及了两种设计模块,分别为:策略模式工厂模式

策略模式:一般用于将具体的算法进行抽象及剥离。此项目中,我们的具体算法是说你好

工厂模式:一般用于根据环境来动态的创建BEAN的情况下。引项目中,我们将根据不同国家的人,来返回不同的说你好这个算法。

先给出UML图:

SpeakService

SpeakService即为我们供其它模块调用的说话服务,调用其中的SayHello()来完成说你好功能。

package com.mengyunzhi.demo.dynamicautowire;

/**
 * 你好
 */
public interface SpeakService {
  void sayHello();
}

在其实现类中,我们注入SayHelloFactory,让其来返回正确的SayHelloService,最终调用sayHello()来完成目标。

package com.mengyunzhi.demo.dynamicautowire;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 你好
 */
@Service
public class SpeakServiceImpl implements SpeakService {
  private final
  SayHelloFactory sayHelloFactory; // 说话工厂

  @Autowired
  public SpeakServiceImpl(SayHelloFactory sayHelloFactory) {
    this.sayHelloFactory = sayHelloFactory;
  }

  @Override
  public void sayHello() {
    this.sayHelloFactory.getSayHelloService().sayHello();
  }
}

SayHelloFactory

package com.mengyunzhi.demo.dynamicautowire;

/**
 * 说话工厂
 */
public interface SayHelloFactory {

  void setCountryCode(CountryCode countryCode);

  SayHelloService getSayHelloService();
}

在此,我们增加一个CountryCode表示当前访问者的国家。其实在获取访问者国家时,我们也可以调用其它Bean的其它来实现。

package com.mengyunzhi.demo.dynamicautowire;

/**
 * 国家代码
 */
public enum CountryCode {
  CHINA((byte) 0, "中国"),
  USA((byte) 1, "美国");
  private Byte code;
  private String name;

  CountryCode(Byte code, String name) {
    this.code = code;
    this.name = name;
  }

  public Byte getCode() {
    return code;
  }
  public String getName() {
    return name;
  }
}

使用enum来控制范围,避免Factory在获取Bean时发生异常。

package com.mengyunzhi.demo.dynamicautowire;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 说话工厂
 */
@Service
public class SayHelloFactoryImpl implements SayHelloFactory {
  /**
   * BEAN列表
   */
  private final Map<Byte, SayHelloService> servicesByCode = new HashMap<>();
  /**
   * 国家代码
   */
  private CountryCode countryCode = CountryCode.CHINA;

  @Override
  public void setCountryCode(CountryCode countryCode) {
    this.countryCode = countryCode;
  }

  /**
   * 初始化
   *
   * @param sayHelloServices spring获取到的所以实现了SpeakService的BEAN
   */
  @Autowired
  public void init(List<SayHelloService> sayHelloServices) {
    for (SayHelloService sayHelloService : sayHelloServices) {
      this.register(sayHelloService.getCode(), sayHelloService);
    }
  }

  /**
   * 注册Bean
   *
   * @param code     代码
   * @param sayHelloService BEAN
   */
  private void register(Byte code, SayHelloService sayHelloService) {
    this.servicesByCode.put(code, sayHelloService);
  }

  /**
   * 获取BEAN
   *
   * @return 对应的SayHelloService BEAN
   */
  @Override
  public SayHelloService getSayHelloService() {
    return this.servicesByCode.get(this.countryCode.getCode());
  }
}

增加Map<Byte, SayHelloService> servicesByCode来存储对应国家的SayHelloServiceBEAN。增加getSayHelloService()来根据当前国家代码来返回相应的Bean。

SayHelloService

package com.mengyunzhi.demo.dynamicautowire;

/**
 * 说话
 */
public interface SayHelloService {
  void sayHello();

  Byte getCode();
}

sayHello()方法抽离,getCode()以获取国家代码。

中国人你好

package com.mengyunzhi.demo.dynamicautowire;

import org.springframework.stereotype.Component;

/**
 * 中国话
 */
@Component
public class SayHelloServiceChineseImpl implements SayHelloService {
  @Override
  public void sayHello() {
    System.out.println("您好");
  }

  @Override
  public Byte getCode() {
    return CountryCode.CHINA.getCode();
  }
}

美国人Hello

package com.mengyunzhi.demo.dynamicautowire;

import org.springframework.stereotype.Component;

/**
 * 美国话
 */
@Component
public class SayHelloServiceEnglishImpl implements SayHelloService {
  @Override
  public void sayHello() {
    System.out.println("hello");
  }

  @Override
  public Byte getCode() {
    return CountryCode.USA.getCode();
  }
}

测试

package com.mengyunzhi.demo.dynamicautowire;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class SpeakServiceImplTest {
  @Autowired
  SpeakService speakService;
  @Autowired
  SayHelloFactory sayHelloFactory;

  @Test
  public void sayHello() {
    // 默认说你好
    speakService.sayHello();

    // 将国家设置为美国,再说你好
    sayHelloFactory.setCountryCode(CountryCode.USA);
    speakService.sayHello();

    // 将国家设置为中国,再说你好
    sayHelloFactory.setCountryCode(CountryCode.CHINA);
    speakService.sayHello();
  }
}

您好
hello
您好

时序图

增加德国人

增加德国人SayHelloServiceGermanyImpl.

CountryCode中,增加德国.

package com.mengyunzhi.demo.dynamicautowire;

import org.springframework.stereotype.Component;

@Component
public class SayHelloServiceGermanyImpl implements SayHelloService {
  @Override
  public void sayHello() {
    System.out.println("Hallo");
  }

  @Override
  public Byte getCode() {
    return CountryCode.GERMANY.getCode();
  }
}
package com.mengyunzhi.demo.dynamicautowire;

/**
 * 国家代码
 */
public enum CountryCode {
  CHINA((byte) 0, "中国"),
  USA((byte) 1, "美国"),
  GERMANY((byte) 2, "德国");
  private Byte code;
  private String name;

  CountryCode(Byte code, String name) {
    this.code = code;
    this.name = name;
  }

  public Byte getCode() {
    return code;
  }

  public String getName() {
    return name;
  }
}

单元测试

 @Test
  public void sayHello1() {
    // 默认说你好
    speakService.sayHello();

    // 将国家设置为美国,再说你好
    sayHelloFactory.setCountryCode(CountryCode.USA);
    speakService.sayHello();

    // 将国家设置为德国,再说你好
    sayHelloFactory.setCountryCode(CountryCode.GERMANY);
    speakService.sayHello();

    // 将国家设置为中国,再说你好
    sayHelloFactory.setCountryCode(CountryCode.CHINA);
    speakService.sayHello();
  }

测试结果如下:

您好
hello
Hallo
您好

总结

在解决问题时,只所有我们看的不够远,可能是由于自己站的不够高。同样的问题,困惑我了多日,直到近期系统的学习设计模式angular官方教程Spring 实战后,结合近期项目变更带来的新需求,才在使用设计模式解决此问题上有所启发。

上一篇:Java如何实现长图文生成的示例代码

栏    目:JAVA代码

下一篇:Java 栈与队列超详细分析讲解

本文标题:详解spring-boot下如何满足多生产环境中个性化定制功能

本文地址:http://www.codeinn.net/misctech/223091.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有