行為型模式:類和對象如何交互,劃分責(zé)任和算法蚕脏,即對象之間通信。
概念
所謂責(zé)任鏈侦锯,多個對象組成一條鏈驼鞭,每個對象有其不同的處理邏輯,將一個請求從鏈的的首端發(fā)出尺碰,沿著鏈的路徑依次傳遞給鏈上的每個對象挣棕,直到有對象處理這個請求為止。
使用場景
- 多個對象可以處理同一個請求亲桥,但具體由哪個對象處理則在運(yùn)行時動態(tài)決定洛心。
- 在請求處理者不明確的情況下向?qū)€對象中的一個提交一個請求。
- 需要動態(tài)處理一組對象處理請求题篷。
結(jié)構(gòu)
角色介紹
Handler:抽象處理者角色词身,聲明一個請求處理的方法,并在其中保持一個對下一個處理節(jié)點Handler對象的引用番枚。
ConcreteHandler:具體處理者角色法严,對請求進(jìn)行處理,如果不能處理則將該請求轉(zhuǎn)發(fā)給下一個節(jié)點上的處理對象葫笼。
實例
簡單是實現(xiàn)深啤,這里就不介紹了,網(wǎng)上資源一大把渔欢,但是工作中實際很少這樣使用墓塌,因為很不方便,下面介紹中工作中改造過的責(zé)任鏈模式
- 首先創(chuàng)建一個接口奥额,抽象出鏈上對象要處理的方法run和直接方法前的資格判斷can苫幢,如下
/**
* 優(yōu)惠券發(fā)放單元接口
*/
public interface ICouponGrantProcessCell {
/**
* 任務(wù)單元名稱.
* @return Sting
*
*/
String getName();
/**
* 是否可以運(yùn)行本任務(wù)單元.
* @param param
* @param context
* @return
*/
boolean can(CouponGrantParam param, CouponGrantProcessContext context);
/**
* 執(zhí)行本任務(wù)單元.
* @param param
* @param context
* @return
* @throws Exception
*/
boolean run(CouponGrantParam param, CouponGrantProcessContext context) throws Exception;
}
- 然后新建一個抽象基礎(chǔ)類,用來抽象具體處理業(yè)務(wù)的handler
/**
* 優(yōu)惠券發(fā)放過程單元父類
*/
public abstract class BaseCouponGrantProcessCell implements ICouponGrantProcessCell {
protected Logger logger = LoggerFactory.getLogger(getClass());
@Override
public String getName() {
return getClass().getName();
}
@Override
public boolean can(CouponGrantParam param, CouponGrantProcessContext context) {
return true;
}
@Override
public boolean run(CouponGrantParam param, CouponGrantProcessContext context) throws Exception {
boolean resultFlag = true;
try {
logger.info("\n----開始執(zhí)行:" + getName());
// 1:子類執(zhí)行下單過程單元
resultFlag = runing(param, context);
// 2:下面保存日志
////////////////////////
} catch (Exception e) {
logger.error("下單過程執(zhí)行到" + getName() + "出錯", e);
throw new Exception(e);
}
return resultFlag;
}
public abstract boolean runing(CouponGrantParam param, CouponGrantProcessContext context) throws Exception;
}
- 具體業(yè)務(wù)處理子類1垫挨,這里的具體業(yè)務(wù)不用關(guān)心
/**
* 【優(yōu)惠券發(fā)放】參數(shù)為空驗證
*/
import org.springframework.core.annotation.Order;
@Order(1)
@Component
public class ParamEmptyValidateCell extends BaseCouponGrantProcessCell {
@Autowired
private IConsumerService consumerService;
@Autowired
private MarketingActivityService marketingActivityService;
@Autowired
private IStoreService storeService;
@Override
public boolean runing(CouponGrantParam param, CouponGrantProcessContext context) throws Exception {
if (param == null)
throw new BusinessException("【優(yōu)惠券發(fā)放】參數(shù)CouponGrantParam不能為空");
if (param.getConsumerId() == null)
throw new BusinessException("【優(yōu)惠券發(fā)放】消費(fèi)者ID不能為空");
if (param.getActivityId() == null)
throw new BusinessException("【優(yōu)惠券發(fā)放】活動ID不能為空");
if (param.getShopId() == null)
throw new BusinessException("【優(yōu)惠券發(fā)放】ShopId不能為空");
Consumer consumer = consumerService.getConsumerById(param.getConsumerId());
if (null == consumer) {
throw new BusinessException("【優(yōu)惠券發(fā)放】消費(fèi)者信息不存在");
}
context.setConsumer(consumer);
MarketingActivity marketingActivity = marketingActivityService.getMarketingActivity(param.getActivityId());
if (null == marketingActivity) {
throw new BusinessException("【優(yōu)惠券發(fā)放】營銷活動信息不存在");
}
context.setMarketingActivity(marketingActivity);
PointPlace pointPlace = storeService.getStoreByPointId(param.getShopId());
if (null == pointPlace) {
throw new BusinessException("【優(yōu)惠券發(fā)放】店鋪信息不存在");
}
context.setPointPlace(pointPlace);
return true;
}
}
具體業(yè)務(wù)處理子類2
/**
* 【優(yōu)惠券發(fā)放】優(yōu)惠券發(fā)放過程處理
*/
import org.springframework.core.annotation.Order;
@Order(2)
@Component
public class CouponGrantCell extends BaseCouponGrantProcessCell {
@Autowired MCouponConsumerService mCouponConsumerService;
@Override
public boolean can(CouponGrantParam param, CouponGrantProcessContext context) {
return param.getWhetherGrant();
}
@Override
public boolean runing(CouponGrantParam param, CouponGrantProcessContext context) throws Exception {
// 最終領(lǐng)取的優(yōu)惠券信息
List<MCouponConsumer> couponConsumers = new ArrayList<MCouponConsumer>();
PointPlace pointPlace = context.getPointPlace();
// 發(fā)放優(yōu)惠券
List<MarketingActivityCoupon> gettableCoupons = context.getGettableCoupons();
// 生成領(lǐng)取批次韩肝,用戶單次領(lǐng)取的批次號一致
String getBatch = RandomUtil.getCharAndNumr(16);
gettableCoupons.parallelStream().forEachOrdered(activityCoupon -> {
// 取得此份權(quán)益發(fā)放張數(shù)(打包發(fā)放數(shù)量)
int packageQty = activityCoupon.getPackageQty();
for (int i = 0; i < packageQty; i++) {
MCouponConsumer mCouponConsumer=mCouponConsumerService.getCouponConsumer(activityCoupon,System.currentTimeMillis());
mCouponConsumer.setConsumerId(param.getConsumerId());
mCouponConsumer.setMarketingActivityId(param.getActivityId());
mCouponConsumer.setMarketingType(1);
mCouponConsumer.setGetBatch(getBatch);
mCouponConsumer.setShopId(pointPlace.getId());
mCouponConsumer.setShopName(pointPlace.getPointName());
mCouponConsumerService.saveMCouponConsumer(mCouponConsumer);
couponConsumers.add(mCouponConsumer);
}
});
context.setCouponConsumers(couponConsumers);
return true;
}
}
- 新建責(zé)任鏈執(zhí)行過程管理器
/**
* 優(yōu)惠券發(fā)放任務(wù)管理器
*/
public class CouponGrantProcess {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 自動注入
*/
@Resource
private List<ICouponGrantProcessCell> tasks;
public void start(CouponGrantParam param, CouponGrantProcessContext context) throws Exception {
for (int index = 0; index < this.tasks.size(); index++) {
ICouponGrantProcessCell task = this.tasks.get(index);
boolean flag = task.can(param, context);
if (flag) {
try {
boolean isNext = task.run(param, context);
if (!isNext) {
break;
}
} catch (Exception e) {
logger.error("終止處理該couponGrantProcess", e);
throw e;
}
}
}
}
}
- 調(diào)用責(zé)任鏈
@Autowired
private CouponGrantProcess couponGrantProcess;
couponGrantProcess.start(param, context);
從改造后的責(zé)任鏈中,可以很明顯的看出九榔,鏈上新添加處理類的話哀峻,特別方便涡相,同時,管理起來也很方便剩蟀。
優(yōu)化備注(主要是簡化xml文件):
1催蝗、通過Spring自動注入list集合
2、通過使用springframework的Order注解指定bean實例初始化加載順序育特,可以用來指定責(zé)任鏈的執(zhí)行順序丙号,避免在xml文件中指定