VppResponseCoefficientHelper.java 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package com.usky.vpp.util;
  2. import com.usky.common.core.exception.BusinessException;
  3. import org.springframework.util.StringUtils;
  4. import java.math.BigDecimal;
  5. /**
  6. * 响应量系数区间:结构化边界校验、匹配、重叠判断与展示串拼装。
  7. */
  8. public final class VppResponseCoefficientHelper {
  9. private VppResponseCoefficientHelper() {
  10. }
  11. /**
  12. * 由结构化边界构建区间并校验。
  13. */
  14. public static Range of(BigDecimal lower, BigDecimal upper,
  15. Boolean lowerInclusive, Boolean upperInclusive) {
  16. if (lower == null && upper == null) {
  17. throw new BusinessException("响应量系数下限与上限不能同时为空");
  18. }
  19. boolean lowerInc = lower != null && Boolean.TRUE.equals(lowerInclusive);
  20. boolean upperInc = upper != null && Boolean.TRUE.equals(upperInclusive);
  21. if (lower != null && upper != null && lower.compareTo(upper) >= 0) {
  22. throw new BusinessException("响应量系数区间下限必须小于上限");
  23. }
  24. return new Range(lower, upper, lowerInc, upperInc);
  25. }
  26. public static boolean matches(BigDecimal lower, BigDecimal upper,
  27. Boolean lowerInclusive, Boolean upperInclusive,
  28. BigDecimal coefficient) {
  29. return coefficient != null && of(lower, upper, lowerInclusive, upperInclusive).contains(coefficient);
  30. }
  31. public static boolean matches(Range range, BigDecimal coefficient) {
  32. return coefficient != null && range != null && range.contains(coefficient);
  33. }
  34. public static boolean overlaps(Range left, Range right) {
  35. return left != null && right != null && left.overlaps(right);
  36. }
  37. /** 拼装展示串,如 [0.6,0.8)、<0.6、>1.4。 */
  38. public static String format(BigDecimal lower, BigDecimal upper,
  39. Boolean lowerInclusive, Boolean upperInclusive) {
  40. return of(lower, upper, lowerInclusive, upperInclusive).format();
  41. }
  42. public static String format(Range range) {
  43. return range == null ? null : range.format();
  44. }
  45. /**
  46. * 解析历史字符串区间,仅供数据迁移使用。
  47. */
  48. public static Range parse(String expression) {
  49. if (!StringUtils.hasText(expression)) {
  50. throw new BusinessException("响应量系数不能为空");
  51. }
  52. String value = expression.trim().replace(',', ',').replace(" ", "");
  53. try {
  54. if (value.startsWith("<=")) {
  55. return new Range(null, new BigDecimal(value.substring(2)), false, true);
  56. }
  57. if (value.startsWith("<")) {
  58. return new Range(null, new BigDecimal(value.substring(1)), false, false);
  59. }
  60. if (value.startsWith(">=")) {
  61. return new Range(new BigDecimal(value.substring(2)), null, true, false);
  62. }
  63. if (value.startsWith(">")) {
  64. return new Range(new BigDecimal(value.substring(1)), null, false, false);
  65. }
  66. if ((value.startsWith("[") || value.startsWith("("))
  67. && (value.endsWith("]") || value.endsWith(")"))) {
  68. String[] bounds = value.substring(1, value.length() - 1).split(",", -1);
  69. if (bounds.length != 2) {
  70. throw new IllegalArgumentException();
  71. }
  72. BigDecimal lower = new BigDecimal(bounds[0]);
  73. BigDecimal upper = new BigDecimal(bounds[1]);
  74. if (lower.compareTo(upper) >= 0) {
  75. throw new BusinessException("响应量系数区间下限必须小于上限");
  76. }
  77. return new Range(lower, upper, value.startsWith("["), value.endsWith("]"));
  78. }
  79. } catch (NumberFormatException ex) {
  80. throw new BusinessException("响应量系数格式无效");
  81. }
  82. throw new BusinessException("响应量系数格式无效,示例:[0.6,0.8)、<0.6、>1.4");
  83. }
  84. public static final class Range {
  85. private final BigDecimal lower;
  86. private final BigDecimal upper;
  87. private final boolean lowerInclusive;
  88. private final boolean upperInclusive;
  89. private Range(BigDecimal lower, BigDecimal upper, boolean lowerInclusive, boolean upperInclusive) {
  90. this.lower = lower;
  91. this.upper = upper;
  92. this.lowerInclusive = lowerInclusive;
  93. this.upperInclusive = upperInclusive;
  94. }
  95. public BigDecimal getLower() {
  96. return lower;
  97. }
  98. public BigDecimal getUpper() {
  99. return upper;
  100. }
  101. public boolean isLowerInclusive() {
  102. return lowerInclusive;
  103. }
  104. public boolean isUpperInclusive() {
  105. return upperInclusive;
  106. }
  107. public boolean contains(BigDecimal value) {
  108. if (lower != null) {
  109. int comparison = value.compareTo(lower);
  110. if (comparison < 0 || (comparison == 0 && !lowerInclusive)) {
  111. return false;
  112. }
  113. }
  114. if (upper != null) {
  115. int comparison = value.compareTo(upper);
  116. if (comparison > 0 || (comparison == 0 && !upperInclusive)) {
  117. return false;
  118. }
  119. }
  120. return true;
  121. }
  122. public boolean overlaps(Range other) {
  123. return upperAllows(other.lower, other.lowerInclusive)
  124. && other.upperAllows(lower, lowerInclusive);
  125. }
  126. public String format() {
  127. if (lower == null && upper != null) {
  128. return (upperInclusive ? "<=" : "<") + upper.stripTrailingZeros().toPlainString();
  129. }
  130. if (upper == null && lower != null) {
  131. return (lowerInclusive ? ">=" : ">") + lower.stripTrailingZeros().toPlainString();
  132. }
  133. String left = lowerInclusive ? "[" : "(";
  134. String right = upperInclusive ? "]" : ")";
  135. return left + lower.stripTrailingZeros().toPlainString()
  136. + "," + upper.stripTrailingZeros().toPlainString() + right;
  137. }
  138. private boolean upperAllows(BigDecimal otherLower, boolean otherLowerInclusive) {
  139. if (upper == null || otherLower == null) {
  140. return true;
  141. }
  142. int comparison = upper.compareTo(otherLower);
  143. return comparison > 0 || (comparison == 0 && upperInclusive && otherLowerInclusive);
  144. }
  145. }
  146. }