好好的“代码优化”是怎么一步步变成“过度设计”的
public Integer parseSaleType(String saleTypeStr){
if(saleTypeStr == null || saleTypeStr.equals("")){
return null;
}
if(saleTypeStr.equals("JX")){
return 1;
}
return null;
}
//saleTypeStr == null
Objects.isNull(saleTypeStr)
容易漏逻辑,尽量使用现成的方法
//if(saleTypeStr == null || saleTypeStr.equals(""))
if(StringUtils.isBlank(saleTypeStr))
//if(saleTypeStr.equals("JX"))
if("JX".equals(saleTypeStr))
private static final String JX_SALE_TYPE_STR = "JX";
private static final Integer JX_SALE_TYPE_INT = 1;
//public Integer parseSaleType(String saleTypeStr)
public static Integer parseSaleType(String saleTypeStr)
方法本身跟所在类的实例对象状态无关,且不会诱发线程安全问题,故符合被定义为static的条件,可先于对象创建在方法区,防止每个对象创建一次的时候,堆内存创建一次。
private static final String JX_SALE_TYPE_STR = "JX";
private static final Integer JX_SALE_TYPE_INT = 1;
public static Integer parseSaleType(String saleTypeStr){
if(JX_SALE_TYPE_STR.equals(saleTypeStr)){
return JX_SALE_TYPE_INT;
}
return null;
}
public static Integer parseSaleType(String saleTypeStr){
return JX_SALE_TYPE_STR.equals(saleTypeStr) ? JX_SALE_TYPE_INT : null;
}
public static Integer parseSaleType(String saleTypeStr){
Optional.ofNullable(saleTypeStr).filter(JX_SALE_TYPE_STR::equals).map(o -> JX_SALE_TYPE_INT).orElse(null);
}
- 未来除了一种逻辑分支外,还会扩展其他分支,并且有被扩展的可能;
- 虽然还是一种逻辑分支,但是判断的内容变长了,跟上下文和调用状态有关;
- 虽然还是一种逻辑分支,但是逻辑总在调整;
- 一处定义,多点引用;
public enum SaleTypeStrEnum{
JX,
// OTHERS
;
}
public enum SaleTypeIntEnum{
JX(1),
// OTHERS
;
private Integer code;
}
public enum SaleTypeStrEnum{
JX,
// OTHERS
;
public static SaleTypeStrEnum getByName(String saleTypeStr){
for (SaleTypeStrEnum value : SaleTypeStrEnum.values()) {
if(value.name().equals(saleTypeStr)){
return value;
}
}
return null;
}
}
public enum SaleTypeStrEnum{
JX,
// OTHERS
;
/**
* 预热转换关系到内存
*/
private static Map<String, SaleTypeStrEnum> NAME_MAP = Arrays.stream(SaleTypeStrEnum.values()).collect(Collectors.toMap(SaleTypeStrEnum::name, Function.identity()));
public static SaleTypeStrEnum getByName(String saleTypeStr){
return NAME_MAP.get(saleTypeStr);
}
}
这样每次检索就是O(1)了,那么最终方法体内也能使用switch管理原本的if-else
public static Integer parseSaleType(String saleTypeStr){
switch(SaleTypeStrEnum.getByName(saleTypeStr)){
case JX:return SaleTypeIntEnum.JX.getCode();
// OTHERS
default:return null;
}
}

public enum SaleTypeRelEnum {
// 不在分别定义两类变量,而是直接定义变量映射关系
JX("JX", 1),
// OTHERS
;
private String fromCode;
private Integer toCode;
private static Map<String, SaleTypeRelEnum> FROM_CODE_MAP = Arrays.stream(SaleTypeRelEnum.values()).collect(Collectors.toMap(SaleTypeRelEnum::getFromCode, Function.identity()));
public static SaleTypeRelEnum get(String saleTypeStr){
return FROM_CODE_MAP.get(saleTypeStr);
}
public static Integer parseCode(String saleTypeStr){
return Optional.ofNullable(SaleTypeRelEnum.get(saleTypeStr)).map(SaleTypeRelEnum::getToCode).orElse(null);
}
}
如果将转关系作为枚举,那么从职责上划分,转换这个动作应该是封闭在枚举内的固有行为,而不该暴露在外,故原来对方法的引用其实应该转为对关系枚举中 SaleTypeEnum::parseCode 方法的引用,O(1)检索且封闭性良好,同时支持更多简单单向映射关系的管理,要是以后出现的新场景都是这种关系,那够扛很久嘞。
/**
* 定义策略接口
*/
public interface SaleTypeParseStrategy{
Integer parse(SaleTypeParseContext saleTypeParseContext);
}
/**
* 策略实现
*/
public class JxSaleTypeParseStrategy implements SaleTypeParseStrategy{
public Integer parse(SaleTypeParseContext saleTypeParseContext) {
return SaleTypeIntEnum.JX.getCode();
}
}
/**
* 调用上下文
*/
public class SaleTypeParseContext{
private SaleTypeStrEnum saleTypeStr;
private SaleTypeParseStrategy parseStrategy;
public Integer pasre(){
return parseStrategy.parse(this);
}
}
public static Integer parseSaleType(String saleTypeStr){
SaleTypeStrEnum saleTypeEnum = SaleTypeStrEnum.getByName(saleTypeStr);
SaleTypeParseContext context = new SaleTypeParseContext();
context.setSaleTypeStr(saleTypeEnum);
switch(saleTypeStr){
// 策略路由
case JX:context.setParseStrategy(new JxSaleTypeParseStrategy());break;
// 继续扩展
default:return null;
}
return context.parse();
}
public static class SaleTypeParseStrategyContainer{
public final static Map<SaleTypeStrEnum, SaleTypeParseStrategy> STRATEGY_MAP = new HashMap<>();
public void init(){
STRATEGY_MAP.put(SaleTypeStrEnum.JX, new JxSaleTypeParseStrategy());
// 继续拓展
}
public Integer parse(SaleTypeParseContext saleTypeParseContext){
return Optional.ofNullable(STRATEGY_MAP.get(saleTypeParseContext.getSaleTypeStr())).map(strategy-> strategy.parse(saleTypeParseContext)).orElse(null);
}
}
容器内手动创建各个策略的实现的单例后进行托管,那调用方只需要去构建上下文就好了,实际调用的方法更换为 SaleTypeParseStrategyContainer::parse,那后续无论策略如何丰富,调用方都不需要再感知这部分变化。后续出现了新的策略实现,则在工厂内继续追加路由表即可。
public interface SaleTypeParseStrategy{
Integer parse(SaleTypeParseContext saleTypeParseContext);
// 所支持的情况
SaleTypeStrEnum support();
}
public class JxSaleTypeParseStrategy implements SaleTypeParseStrategy{
public Integer parse(SaleTypeParseContext saleTypeParseContext) {
return SaleTypeIntEnum.JX.getCode();
}
public SaleTypeStrEnum support() {
return SaleTypeStrEnum.JX;
}
}
public static class SaleTypeParseStrategyContainer{
public final static Map<SaleTypeStrEnum, SaleTypeParseStrategy> STRATEGY_MAP = new HashMap<>();
private List<SaleTypeParseStrategy> parseStrategyList;
public void init(){
parseStrategyList.stream().forEach(strategy-> STRATEGY_MAP.put(strategy.support(), strategy));
}
public Integer parse(SaleTypeParseContext saleTypeParseContext){
return Optional.ofNullable(STRATEGY_MAP.get(saleTypeParseContext.getSaleTypeStr())).map(strategy-> strategy.parse(saleTypeParseContext)).orElse(null);
}
}
public interface SaleTypeParseStrategy{
Integer parse(SaleTypeParseContext saleTypeParseContext);
// 用于判断是否支持
boolean support(SaleTypeParseContext saleTypeParseContext);
}
public class JxSaleTypeParseStrategy implements SaleTypeParseStrategy{
public Integer parse(SaleTypeParseContext saleTypeParseContext) {
return SaleTypeIntEnum.JX.getCode();
}
public boolean support(SaleTypeParseContext saleTypeParseContext) {
return SaleTypeStrEnum.JX.equals(saleTypeParseContext.getSaleTypeStr());
}
}
public static class SaleTypeParseStrategyContainer{
private List<SaleTypeParseStrategy> parseStrategyList;
public Integer parse(SaleTypeParseContext saleTypeParseContext){
return parseStrategyList.stream()
.filter(strategy->strategy.support(saleTypeParseContext))
.findAny()
.map(strategy->strategy.parse(saleTypeParseContext))
.orElse(null);
}
}
- 植入Diamond走走动态配置开关的思路;
- 植入QLExpress搞搞逻辑表达式的思路;
- 把策略实现改成HsfProvider走分布式调用思路;
- 借助一些成熟的网关走服务路由的的调用思路;
微信赞赏
支付宝扫码领红包
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。侵权投诉:375170667@qq.com