目录
前言
采用简单的注解方式进行业务策略模式
场景举例
实现方案
基本代码准备
基本功能接口定义
定义注解与不同的策略实现
业务实际使用
测试及结果展示
采用组合的注解方式进行业务策略模式
场景举例
订单来源pc端支付,然后不同支付方式和会员等级有不同策略
订单来源手机端支付,然后不同支付方式和会员等级有不同策略
采用复杂的注解方式进行业务策略模式
场景举例
前言
平时的开发中往往需要嵌套的策略去解决一定的业务或底层问题,如果在上一层已经通过工厂模式和策略模式的综合使用_xiaofeng10330111的博客-CSDN博客该方式进行了相关的策略模式的使用,但是在紧接着的下层逻辑上再次使用相同逻辑的策略往往会创建大量的工厂去实现,各策略也需要向工厂写入内容,这个时候我往往会使用注解方式去实现对应的下层策略模式,主要采用方式写三个业务场景来使用展示,以便供大家记录,写的不对的可留言指正。
采用简单的注解方式进行业务策略模式
场景举例
假设有业务场景,前期通过整体的一些配置方案在线上共用的针对现有业务上做了通用配置,例如在商家售卖的商品具有资质以及业务管控,即配置一些商店(单店、总店、品牌门店等)可售卖的商品类目有指定的配置,在指定配置下进行具体商品的售卖,原来线上的配置在业务发展过程中发现有些门店的有些售卖类目可以进行个性化管控(跨境门店可单独售卖一些指定的类目,这些类目符合国家要求)但对原配置不产生影响,我们配置了针对特定门店或品牌等可以进行有自己的个性化业务个性化配置,现要求个性化业务上通过配置对指定门店有不同的策略。假设其他上层策略我们已经实现,就单独个性化配置的控制规则上通过注解实现控制规则的策略实现。
实现方案
基本代码准备
业务上个性换配置的主要信息如下
package org.zyf.javabasic.designpatterns.strategy.base;
import lombok.Builder;
import lombok.Data;
import java.util.List;
@Data
@Builder
public class OverrangeBusinessScope {
private long id;
private String name;
private int type;
private String effectRanges;
private int controlRule;
private int validateRule;
private List relationCates;
private long ctime;
private long utime;
private String cname;
private String uname;
}
其中控制规则的常量选择如下:(只进行控制规则的,其他规则不做分析)
package org.zyf.javabasic.designpatterns.strategy.base;
public class OverrangeContants {
public static class BizScopeControlRule {
public static final int onLY = 1;
public static final int NEED = 2;
public static final int NO = 3;
}
}
基本功能接口定义
按照不同的控制规则返回实际个性化门店或品牌的实际可以售卖的类目情况,
package org.zyf.javabasic.designpatterns.strategy.base;
import java.util.Collection;
public interface ControlRuleHandler {
Collection getCagegoryIds(CagegoryDealInfo cagegoryDealInfo) throws Exception;
}
其中需要入参为超范围经营类目处理整合信息CagegoryDealInfo,需要传入当前平台已配置的通用化可售卖类目情况以及对应业务个性化配置的干预类目信息,具体内容如下:
package org.zyf.javabasic.designpatterns.strategy.base;
import lombok.Builder;
import lombok.Data;
import java.util.Collection;
@Data
@Builder
public class CagegoryDealInfo {
private Collection bgCategoryIds;
private Collection bgCategoryIdsForBizScope;
}
定义注解与不同的策略实现
基本注解定义
package org.zyf.javabasic.designpatterns.strategy.base;
import org.springframework.stereotype.Service;
import java.lang.annotation.documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Service
public @interface ControlRuleHandlerType {
int controlRuleType();
}
策略1:控制规则,要求只返回个性化指定类目作为可售卖类目
package org.zyf.javabasic.designpatterns.strategy.base;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
@ControlRuleHandlerType(controlRuleType = OverrangeContants.BizScopeControlRule.ONLY)
@Service
public class ControlRuleForDesignatedHandler implements ControlRuleHandler {
@Autowired
private ProductCategoryService productCategoryService;
@Override
public Collection getCagegoryIds(CagegoryDealInfo cagegoryDealInfo) throws Exception {
return productCategoryService.fetchAllIdPathByCategoryId(cagegoryDealInfo.getBgCategoryIdsForBizScope());
}
}
策略2:控制规则,要求在原配置上增加个性化指定的一些类目,整体作为可售卖类目的情况
package org.zyf.javabasic.designpatterns.strategy.base;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@ControlRuleHandlerType(controlRuleType = OverrangeContants.BizScopeControlRule.NEED)
@Service
public class ControlRuleForIncludeHandler implements ControlRuleHandler {
@Autowired
private ProductCategoryService productCategoryService;
@Override
public Collection getCagegoryIds(CagegoryDealInfo cagegoryDealInfo) throws Exception {
Collection bgCategoryIds = cagegoryDealInfo.getBgCategoryIds();
Collection bgCategoryIdsForBizScope = cagegoryDealInfo.getBgCategoryIdsForBizScope();
if (CollectionUtils.isEmpty(bgCategoryIds) && CollectionUtils.isEmpty(bgCategoryIdsForBizScope)) {
return bgCategoryIds;
}
Collection finalCategoryIds = new java.util.ArrayList(Collections.EMPTY_SET);
Set allCategorysForBizScope = new HashSet<>(productCategoryService.fetchAllIdPathByCategoryId(bgCategoryIdsForBizScope));
finalCategoryIds.addAll(bgCategoryIds);
finalCategoryIds.addAll(allCategorysForBizScope);
return finalCategoryIds;
}
}
策略3:控制规则,要求在原配置上去除个性化指定的一些类目,然后整体作为可售卖类目的情况
package org.zyf.javabasic.designpatterns.strategy.base;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
@ControlRuleHandlerType(controlRuleType = OverrangeContants.BizScopeControlRule.NO)
@Service
public class ControlRuleForNotContainHandler implements ControlRuleHandler {
@Autowired
private ProductCategoryService productCategoryService;
@Override
public Collection getCagegoryIds(CagegoryDealInfo cagegoryDealInfo) throws Exception {
Collection bgCategoryIds = cagegoryDealInfo.getBgCategoryIds();
Collection bgCategoryIdsForBizScope = cagegoryDealInfo.getBgCategoryIdsForBizScope();
if (CollectionUtils.isEmpty(bgCategoryIds) && CollectionUtils.isEmpty(bgCategoryIdsForBizScope)) {
return bgCategoryIds;
}
if (CollectionUtils.isEmpty(bgCategoryIds)) {
return bgCategoryIds;
}
Set allCategorysForBizScope = new HashSet<>(productCategoryService.fetchAllIdPathByCategoryId(bgCategoryIdsForBizScope));
return bgCategoryIds.stream().filter(bgCategoryId -> !allCategorysForBizScope.contains(bgCategoryId)).collect(Collectors.toList());
}
}
其中设置相关类目级别设置的可能是级层比较低,通过其他service进行补齐,本次不做复杂处理,只简单的为了测试随意写了一个,与实际处理无关,只为了测试。
package org.zyf.javabasic.designpatterns.strategy.base;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@Service
public class ProductCategoryService {
public Collection fetchAllIdPathByCategoryId(Collection categoryIds) {
Collection allIdPath = new ArrayList(Collections.EMPTY_SET);
if (CollectionUtils.isEmpty(categoryIds)) {
return allIdPath;
}
categoryIds.forEach(categoryId -> {
if (categoryId == 1) {
allIdPath.add(1L);
return;
}
if (categoryId == 2) {
allIdPath.add(2L);
return;
}
if (categoryId == 3) {
allIdPath.add(3L);
return;
}
if (categoryId == 4) {
allIdPath.add(4L);
return;
}
if (categoryId == 5) {
allIdPath.add(5L);
}
});
return allIdPath;
}
}
业务实际使用
package org.zyf.javabasic.designpatterns.strategy.base;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Log4j2
public class BizService {
private Map brandControlRuleHandleMap;
@Autowired
public void setBrandControlRuleHandleMap(List brandControlRuleHandlers) {
// 注入各种类型的品牌控制规则处理类
brandControlRuleHandleMap = brandControlRuleHandlers.stream().collect(
Collectors.toMap(orderHandler -> AnnotationUtils.findAnnotation(orderHandler.getClass(), ControlRuleHandlerType.class).controlRuleType(),
v -> v, (v1, v2) -> v1));
}
public Collection getCagegoryIdsByControlRule(OverrangeBusinessScope overrangeBusinessScope, Collection bgCategoryIds) throws Exception {
if (null == overrangeBusinessScope && CollectionUtils.isEmpty(overrangeBusinessScope.getRelationCates())) {
return Lists.newArrayList();
}
ControlRuleHandler controlRuleHandler = brandControlRuleHandleMap.get(overrangeBusinessScope.getControlRule());
Collection bgCategoryIdsForBrand = overrangeBusinessScope.getRelationCates();
CagegoryDealInfo cagegoryDealInfo = CagegoryDealInfo.builder()
.bgCategoryIds(bgCategoryIds)
.bgCategoryIdsForBizScope(bgCategoryIdsForBrand)
.build();
return controlRuleHandler.getCagegoryIds(cagegoryDealInfo);
}
}
测试及结果展示
基本测试用例如下
package org.zyf.javabasic.designpatterns.strategy.base;
import lombok.extern.slf4j.Slf4j;
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;
import org.zyf.javabasic.ZYFApplication;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ZYFApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class baseStrategyTest {
@Autowired
private BizService bizService;
@Test
public void testBizFunction() throws Exception {
log.info("业务场景1---业务原配置类目内容为(1,2,3),现在个性化处理配置需要在原类目基础上增加以下类目(4,5)");
Long[] bgCategoryIdInfo1 = {1L,2L,3L};
Collection bgCategoryIds1= Arrays.asList(bgCategoryIdInfo1);
Long[] relationCateInfo1 = {4L,5L};
List relationCates1 = Arrays.asList(relationCateInfo1);
OverrangeBusinessScope overrangeBusinessScope1 = OverrangeBusinessScope.builder()
.controlRule(OverrangeContants.BizScopeControlRule.NEED)
.relationCates(relationCates1).build();
log.info("业务场景1情况下最终得到的业务类目为:{}",bizService.getCagegoryIdsByControlRule(overrangeBusinessScope1,bgCategoryIds1));
log.info("业务场景2---业务原配置类目内容为(1,2,3),现在个性化处理配置需要在原类目基础上不能包含以下类目(1,2)");
Long[] bgCategoryIdInfo2 = {1L,2L,3L};
Collection bgCategoryIds2= Arrays.asList(bgCategoryIdInfo2);
Long[] relationCateInfo2 = {1L,2L};
List relationCates2 = Arrays.asList(relationCateInfo2);
OverrangeBusinessScope overrangeBusinessScope2 = OverrangeBusinessScope.builder()
.controlRule(OverrangeContants.BizScopeControlRule.NO)
.relationCates(relationCates2).build();
log.info("业务场景2情况下最终得到的业务类目为:{}",bizService.getCagegoryIdsByControlRule(overrangeBusinessScope2,bgCategoryIds2));
log.info("业务场景3---业务原配置类目内容为(1,2,3, 4, 5),现在个性化处理配置需要不在意原有配置,当前只能售卖类目为(2,5)");
Long[] bgCategoryIdInfo3 = {1L,2L,3L,4L,5L};
Collection bgCategoryIds3= Arrays.asList(bgCategoryIdInfo3);
Long[] relationCateInfo3 = {2L,5L};
List relationCates3 = Arrays.asList(relationCateInfo3);
OverrangeBusinessScope overrangeBusinessScope3 = OverrangeBusinessScope.builder()
.controlRule(OverrangeContants.BizScopeControlRule.ONLY)
.relationCates(relationCates3).build();
log.info("业务场景3情况下最终得到的业务类目为:{}",bizService.getCagegoryIdsByControlRule(overrangeBusinessScope3,bgCategoryIds3));
}
}
测试结果展示
采用组合的注解方式进行业务策略模式
场景举例
假设我们在某个平台购物的时候,在订单生成后,我们对订单价格营销手段很简单,就是根据订单的来源(手机端或pc端)、支付方式(微信、支付宝或本地钱包)、对应用户的会员等级(新晋会员、白银会员、黄金会员、钻石会员等)等的不同会有不同的策略干预用户可享受的权益,具体如下:
订单来源pc端支付,然后不同支付方式和会员等级有不同策略
订单来源手机端支付,然后不同支付方式和会员等级有不同策略
此时按照注解方式实现相关的策略。以上场景只是为了我后续写代码方便,其实未必有该场景。
相关代码用空我在写。。。。。
采用复杂的注解方式进行业务策略模式 场景举例
假设我们在某个平台购物的时候,在订单生成后,我们对订单价格营销手段很简单,就是根据订单的来源(手机端或pc端)、支付方式(微信、支付宝或本地钱包)、对应用户的会员等级(新晋会员、白银会员、黄金会员、钻石会员等)等的不同来干预用户可享受的权益,但是有的组合方式享受的权益内容是一样的,具体如下:
订单来源pc端支付,然后不同支付方式和会员等级有不同策略(交叉有相同)
订单来源手机端支付,然后不同支付方式和会员等级有不同策略(交叉有相同)
此时按照注解方式实现相关的策略,要求别写重复策略代码(因为我知道可以按照上面的组合方式改注解标记来实现,然后copy代码就可以)。以上场景只是为了我后续写代码方便,其实未必有该场景。
相关代码用空我在写。。。。。



