当前位置:网站首页>抽奖 ddd 代码
抽奖 ddd 代码
2022-06-23 03:57:00 【duanmy0687】
贫血模型
奖池和奖项
class AwardPool {
int awardPoolId;
List<Award> awards;
public List<Award> getAwards() {
return awards;
}
public void setAwards(List<Award> awards) {
this.awards = awards;
}
......
}
class Award {
int awardId;
int probability;//概率
......
}
设计一个LotteryService,在其中的drawLottery()方法写服务逻辑
//sql查询,将数据映射到AwardPool对象
AwardPool awardPool = awardPoolDao.getAwardPool(poolId);
for (Award award : awardPool.getAwards()) {
//寻找到符合award.getProbability()概率的award
}
DDD工程实现
1. 限界上下文(即模块)
一般尽量用一个模块来表示一个领域的限界上下文
import com.company.team.bussiness.lottery.*;//抽奖上下文
import com.company.team.bussiness.riskcontrol.*;//风控上下文
import com.company.team.bussiness.counter.*;//计数上下文
import com.company.team.bussiness.condition.*;//活动准入上下文
import com.company.team.bussiness.stock.*;//库存上下文
模块内的组织结构
对于模块内的组织结构,一般情况下我们是按照领域对象、领域服务、领域资源库、防腐层等组织方式定义的。
import com.company.team.bussiness.lottery.domain.valobj.*;//领域对象-值对象
import com.company.team.bussiness.lottery.domain.entity.*;//领域对象-实体
import com.company.team.bussiness.lottery.domain.aggregate.*;//领域对象-聚合根
import com.company.team.bussiness.lottery.service.*;//领域服务
import com.company.team.bussiness.lottery.repo.*;//领域资源库
import com.company.team.bussiness.lottery.facade.*;//领域防腐层
2. 领域对象

抽奖(DrawLottery)聚合根和奖池(AwardPool)值对象
抽奖聚合根:抽奖活动的id、该活动下的所有可用奖池列表,
它的一个最主要的领域功能就是根据一个抽奖发生场景(DrawLotteryContext),选择出一个适配的奖池,即chooseAwardPool方法。
chooseAwardPool的逻辑:DrawLotteryContext会带有用户抽奖时的场景信息(抽奖得分或抽奖时所在的城市),DrawLottery会根据这个场景信息,匹配一个可以给用户发奖的AwardPool。
package com.company.team.bussiness.lottery.domain.aggregate;
import ...;
public class DrawLottery {
private int lotteryId; //抽奖id
private List<AwardPool> awardPools; //奖池列表
//getter & setter
public void setLotteryId(int lotteryId) {
if(id<=0){
throw new IllegalArgumentException("非法的抽奖id");
}
this.lotteryId = lotteryId;
}
//根据抽奖入参context选择奖池
public AwardPool chooseAwardPool(DrawLotteryContext context) {
if(context.getMtCityInfo()!=null) {
return chooseAwardPoolByCityInfo(awardPools, context.getMtCityInfo());
} else {
return chooseAwardPoolByScore(awardPools, context.getGameScore());
}
}
//根据抽奖所在城市选择奖池
private AwardPool chooseAwardPoolByCityInfo(List<AwardPool> awardPools, MtCifyInfo cityInfo) {
for(AwardPool awardPool: awardPools) {
if(awardPool.matchedCity(cityInfo.getCityId())) {
return awardPool;
}
}
return null;
}
//根据抽奖活动得分选择奖池
private AwardPool chooseAwardPoolByScore(List<AwardPool> awardPools, int gameScore) {
...}
}
在匹配到一个具体的奖池之后,需要确定最后给用户的奖品是什么。这部分的领域功能在AwardPool内。
package com.company.team.bussiness.lottery.domain.valobj;
import ...;
public class AwardPool {
private String cityIds;//奖池支持的城市
private String scores;//奖池支持的得分
private int userGroupType;//奖池匹配的用户类型
private List<Awrad> awards;//奖池中包含的奖品
//当前奖池是否与城市匹配
public boolean matchedCity(int cityId) {
...}
//当前奖池是否与用户得分匹配
public boolean matchedScore(int score) {
...}
//根据概率选择奖池
public Award randomGetAward() {
int sumOfProbablity = 0;
for(Award award: awards) {
sumOfProbability += award.getAwardProbablity();
}
int randomNumber = ThreadLocalRandom.current().nextInt(sumOfProbablity);
range = 0;
for(Award award: awards) {
range += award.getProbablity();
if(randomNumber<range) {
return award;
}
}
return null;
}
}
与以往的仅有getter、setter的业务对象不同,领域对象具有了行为,对象更加丰满。同时,比起将这些逻辑写在服务内(例如**Service),领域功能的内聚性更强,职责更加明确。
3. 资源库
Repository,资源库对外的整体访问由Repository提供
数据库,分布式缓存,本地缓存
//数据库资源
import com.company.team.bussiness.lottery.repo.dao.AwardPoolDao;//数据库访问对象-奖池
import com.company.team.bussiness.lottery.repo.dao.AwardDao;//数据库访问对象-奖品
import com.company.team.bussiness.lottery.repo.dao.po.AwardPO;//数据库持久化对象-奖品
import com.company.team.bussiness.lottery.repo.dao.po.AwardPoolPO;//数据库持久化对象-奖池
import com.company.team.bussiness.lottery.repo.cache.DrawLotteryCacheAccessObj;//分布式缓存访问对象-抽奖缓存访问
import com.company.team.bussiness.lottery.repo.repository.DrawLotteryRepository;//资源库访问对象-抽奖资源库
package com.company.team.bussiness.lottery.repo;
import ...;
@Repository
public class DrawLotteryRepository {
@Autowired
private AwardDao awardDao;
@Autowired
private AwardPoolDao awardPoolDao;
@AutoWired
private DrawLotteryCacheAccessObj drawLotteryCacheAccessObj;
public DrawLottery getDrawLotteryById(int lotteryId) {
DrawLottery drawLottery = drawLotteryCacheAccessObj.get(lotteryId);
if(drawLottery!=null){
return drawLottery;
}
drawLottery = getDrawLotteyFromDB(lotteryId);
drawLotteryCacheAccessObj.add(lotteryId, drawLottery);
return drawLottery;
}
private DrawLottery getDrawLotteryFromDB(int lotteryId) {
...}
}
4. 防腐层
在一个上下文中,有时需要对外部上下文进行访问。
package com.company.team.bussiness.lottery.facade;
import ...;
@Component
public class UserCityInfoFacade {
@Autowired
private LbsService lbsService;//外部用户城市信息RPC服务
public MtCityInfo getMtCityInfo(LotteryContext context) {
LbsReq lbsReq = new LbsReq();
lbsReq.setLat(context.getLat());
lbsReq.setLng(context.getLng());
LbsResponse resp = lbsService.getLbsCityInfo(lbsReq);
return buildMtCifyInfo(resp);
}
private MtCityInfo buildMtCityInfo(LbsResponse resp) {
...}
}
5. 领域服务
package com.company.team.bussiness.lottery.service.impl
import ...;
@Service
public class LotteryServiceImpl implements LotteryService {
@Autowired
private DrawLotteryRepository drawLotteryRepo;
@Autowired
private UserCityInfoFacade UserCityInfoFacade;
@Autowired
private AwardSendService awardSendService;
@Autowired
private AwardCounterFacade awardCounterFacade;
@Override
public IssueResponse issueLottery(LotteryContext lotteryContext) {
DrawLottery drawLottery = drawLotteryRepo.getDrawLotteryById(lotteryContext.getLotteryId());//获取抽奖配置聚合根
awardCounterFacade.incrTryCount(lotteryContext);//增加抽奖计数信息
AwardPool awardPool = lotteryConfig.chooseAwardPool(bulidDrawLotteryContext(drawLottery, lotteryContext));//选中奖池
Award award = awardPool.randomChooseAward();//选中奖品
return buildIssueResponse(awardSendService.sendAward(award, lotteryContext));//发出奖品实体
}
private IssueResponse buildIssueResponse(AwardSendResponse awardSendResponse) {
...}
}
package ...;
import ...;
@Service
public class LotteryApplicationService {
@Autowired
private LotteryRiskService riskService;
@Autowired
private LotteryConditionService conditionService;
@Autowired
private LotteryService lotteryService;
//用户参与抽奖活动
public Response<PrizeInfo, ErrorData> participateLottery(LotteryContext lotteryContext) {
//校验用户登录信息
validateLoginInfo(lotteryContext);
//校验风控
RiskAccessToken riskToken = riskService.accquire(buildRiskReq(lotteryContext));
...
//活动准入检查
LotteryConditionResult conditionResult = conditionService.checkLotteryCondition(otteryContext.getLotteryId(),lotteryContext.getUserId());
...
//抽奖并返回结果
IssueResponse issueResponse = lotteryService.issurLottery(lotteryContext);
if(issueResponse!=null && issueResponse.getCode()==IssueResponse.OK) {
return buildSuccessResponse(issueResponse.getPrizeInfo());
} else {
return buildErrorResponse(ResponseCode.ISSUE_LOTTERY_FAIL, ResponseMsg.ISSUE_LOTTERY_FAIL)
}
}
private void validateLoginInfo(LotteryContext lotteryContext){
...}
private Response<PrizeInfo, ErrorData> buildErrorResponse (int code, String msg){
...}
private Response<PrizeInfo, ErrorData> buildSuccessResponse (PrizeInfo prizeInfo){
...}
}
边栏推荐
- [leetcode] longest increasing subsequence problem and its application
- MCS: continuous random variable chi square distribution
- Xa mode explanation and code implementation of four Seata modes
- 数据库连接异常:create connection error, url: jdbc:mysql://ip/数据库名, errorCode 0, state 08S01问题处理
- stm32时钟树错误配置导致 开机进入硬中断
- C language stack implementation
- MCS: discrete random variable - uniform distribution
- Web 应用程序安全测试指南
- Seata四大模式之XA模式详解及代码实现
- hash---------history
猜你喜欢
随机推荐
Konva series tutorial 1:what is konva?
Database connection exception: create connection error, url: jdbc: mysql://ip/ Database name, errorcode 0, state 08s01 problem handling
Swiftui 2.0 course notes Chapter 4
View of MySQL introductory learning (III)
JVM原理之完整的一次GC流程
bat中获取bat命令结果
ES6的Array.from方法创建长度为N的undefined数组
JVM原理之内存模型
Web application security testing guide
Jenkins安装部署以及自动构建和发布jar应用
Jenkins installs and deploys and automatically builds and publishes jar applications
奇门遁甲辅助决策软件
Zygote process
VMware network connection error unit network service not found
戏问花门酒家翁
Mongodb sharding principle
Go language -panic and recover
Win11不能录制音频怎么办?Win11无法录入声音的解决方法
Complete the primary school project in 3 days, and teach you to complete the weather broadcast system hand in hand!
[leetcode] longest increasing subsequence problem and its application








