我们在平时开发中遇到最多的问题,无异于实体类属性的变化,可能我们开发出来的接口跟前端要的字段很多不一样,或者需求变更,需要返回的很多内容不一样。
假设我们现在有这么一个需求,返回一个配件的详细信息,也许我们之前返回的格式如下
{
"code" : 200 ,
"data" : {
"brand" : {
"code" : "001" ,
"firstChar" : "�" ,
"id" : 1 ,
"logoUrl" : "http://123.456.789" ,
"name" : "飞利浦" ,
"sort" : 1
},
"code" : "0002" ,
"freeShipping" : false ,
"levelName" : "高级项链" ,
"otherValues" : {
"innerMap" : {
"商品等级" : "国际" ,
"运费设置" : "包邮" ,
"生产厂家" : "飞利浦" ,
"包装规格" : "10" ,
"商品产地" : "呼和浩特"
},
"obj" : {
"$ref" : "$.data.otherValues.innerMap"
}
},
"product" : {
"hotSell" : false ,
"id" : 2459901248443253560 ,
"model" : "朝天DDL" ,
"name" : "项链天窗" ,
"onShelf" : false ,
"price" : {
"begin" : false ,
"normalPrice" : 3000.0000000000
},
"recommend" : false
},
"provider" : {
"code" : "0001" ,
"productProvider" : {
"id" : 2459698718186668856 ,
"logoUrl" : "http://123.456.23.12/12.jpg" ,
"name" : "大众4S店" ,
"productList" : []
},
"status" : false
}
},
"msg" : "操作成功"
}
但是由于现在需求变化,我们需要返回如下格式
{ data: { product: { // 产品信息 id: '', name: '', // 产品名称 imgs: [''], // 产品图片 price: 123, // 价格 }, store: { // 店铺信息 name: '', id: '', logo: '', rate: 4.5, // 评价 collect: 2032, // 收藏数 }, comments: { // 评论 rate: 4.4, // 总评分 list: [ { id: '', content: '', img: [''], ... } ] }, specs: [ // 自定义属性 {name: '商品等级', value: '国际'} ], picTextContent: '<html />' // 图文详情 } }
业务相关有两个接口
/** * 配件商品提供者 */ public interface Provider { /** * 添加商品提供者(包含门店,服务) * @param provider * @return */ boolean addProvider(Provider provider); /** * 移除商品提供者 * @param provider * @return */ boolean removeProdvider(Provider provider); /** * 根据id获取一个商品提供者 * @param id * @return */ Provider findProvider(Long id); /** * 获取所有商品提供者 * @return */ List<Provider> allProvider(); /** * 根据id获取下层商品提供者 * @param id * @return */ List<Provider> findContaint(Long id); }
public interface ProductService { Page<Provider> showProduct(Map<String,Object> params); Provider findProduct(Long id); Long findProviderId(Long id); }
需求变更前,我们定义的配件实体类如下
@Slf4j @Data @NoArgsConstructor public class ProviderProduct implements Provider,ProductService { private Product product; private String code; private Brand brand; private String details; private String levelName; private boolean freeShipping; private DefaultProvider provider; private ExtBeanWrapper otherValues; public ProviderProduct(Product product,String code,Brand brand) { this.product = product; this.code = code; this.brand = brand; } @Override public boolean addProvider(Provider provider) { throw new RuntimeException("不支持此方法"); } @Override public boolean removeProdvider(Provider provider) { throw new RuntimeException("不支持此方法"); } @Override public Provider findProvider(Long id) { return null; } @Override public List<Provider> allProvider() { return null; } @Override public List<Provider> findContaint(Long id) { throw new RuntimeException("不支持此方法"); } @Override public Page<Provider> showProduct(Map<String, Object> params) { ProductDao productDao = SpringBootUtil.getBean(ProductDao.class); int total = productDao.countProductInDefaultProvider(params); List<Provider> providers = Collections.emptyList(); if (total > 0) { PageUtil.pageParamConver(params,false); providers = productDao.findAllProductSimpleByProviderId(params); } return new Page<>(total,providers); } @Override public Provider findProduct(Long id) { ProductDao productDao = SpringBootUtil.getBean(ProductDao.class); OtherPropertyDao otherPropertyDao = SpringBootUtil.getBean(OtherPropertyDao.class); Provider product = productDao.findProductById(id); Map map = ((ProviderProduct) product).getOtherValues().getInnerMap(); Map<String,String> insteadMap = new HashMap<>(); for (Object key : map.keySet()) { log.info("键名为:" + String.valueOf(key)); String name = otherPropertyDao.findNameById(Long.parseLong(String.valueOf(key))); insteadMap.put(name,(String) map.get(key)); } ((ProviderProduct) product).getOtherValues().setObj(insteadMap); return product; } @Override public Long findProviderId(Long id) { ProductDao productDao = SpringBootUtil.getBean(ProductDao.class); return productDao.findProviderIdById(id); } }
/** * 配件提供者工厂 */ public class ProviderFactory { public static ProductService createProviderProduct() { return new ProviderProduct(); } }
Controller如下(有删减)
@Slf4j @RestController public class ProductController { private ProductService productService = ProviderFactory.createProviderProduct(); /** * 展示某个配件商的所有配件(带分页) * @param params * @return */ @Transactional @SuppressWarnings("unchecked") @GetMapping("/productprovider-anon/showproduct") public Result<Page<Provider>> showProduct(@RequestParam Map<String,Object> params) { return Result.success(productService.showProduct(params)); } /** * 查看某一个配件的详细信息 * @param id * @return */ @Transactional @SuppressWarnings("unchecked") @GetMapping("/productprovider-anon/findproduct") public Result<Provider> findProduct(@RequestParam("id") Long id) { return Result.success(productService.findProduct(id)); } }
业务变更后,我们创建新的实体类
@Slf4j @NoArgsConstructor public class ProductDetail implements ProductService,Provider { private ProviderProduct providerProduct = new ProviderProduct(); @Getter @Setter private Long id; @Getter @Setter private String name; @Getter @Setter private List<String> imgUrl; @Getter @Setter private Price price; @Getter @Setter private ProductProvider provider; @Getter @Setter private ExtBeanWrapper otherValues; @Getter @Setter private Integer collectedNum; @Getter @Setter private Double avgStar; @Getter @Setter private List<Evaluate> evaluateList; @Getter @Setter private String details; @Override public Page<Provider> showProduct(Map<String, Object> params) { return providerProduct.showProduct(params); } @Override public Provider findProduct(Long id) { ProductDetailDao productDetailDao = SpringBootUtil.getBean(ProductDetailDao.class); EvaluateClient evaluateClient = SpringBootUtil.getBean(EvaluateClient.class); OtherPropertyDao otherPropertyDao = SpringBootUtil.getBean(OtherPropertyDao.class); Provider product = productDetailDao.findProductById(id); String imgUrlStr = productDetailDao.findImgUrlById(id); String[] imgUrls = imgUrlStr.split(","); ((ProductDetail)product).setImgUrl(Arrays.asList(imgUrls)); List<Evaluate> evaluates = evaluateClient.allEvaluateOfProduct(id, ((ProductDetail) product).getProvider().getId()); ((ProductDetail)product).setEvaluateList(evaluates); OptionalDouble average = evaluates.stream().mapToDouble(Evaluate::getStar).average(); ((ProductDetail)product).setAvgStar(average.getAsDouble()); Map map = ((ProductDetail)product).getOtherValues().getInnerMap(); Map<String,String> insteadMap = new HashMap<>(); map.keySet().stream().forEach(key -> { log.info("键名为:" + String.valueOf(key)); String name = otherPropertyDao.findNameById(Long.parseLong(String.valueOf(key))); insteadMap.put(name,(String) map.get(key)); }); ((ProductDetail)product).getOtherValues().setObj(insteadMap); return product; } @Override public Long findProviderId(Long id) { return providerProduct.findProviderId(id); } @Override public boolean addProvider(Provider provider) { return providerProduct.addProvider(provider); } @Override public boolean removeProdvider(Provider provider) { return providerProduct.removeProdvider(provider); } @Override public Provider findProvider(Long id) { return providerProduct.findProvider(id); } @Override public List<Provider> allProvider() { return providerProduct.allProvider(); } @Override public List<Provider> findContaint(Long id) { return providerProduct.findContaint(id); } }
按照需求一比一定义字段,我们可以看到新类也实现了这两个接口ProductService,Provider,由于我们只需要变更展示配件明细,其他的需求并不需要修改,则我们委托了一个private ProviderProduct providerProduct = new ProviderProduct(),让其适配原有的业务即可,需要变更的是findProduct()方法
dao和mapper省略......
此时要使用新类来跑新需求,我们需要变更工厂的实现类
/** * 配件提供者工厂 */ public class ProviderFactory { public static ProductService createProviderProduct() { return new ProductDetail(); } }
如此我们不需要修改任何原始代码就完成了需求变更,Controller也无需做修改。完全符合开闭原则。
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句