相关业务对象


消费权益业务逻辑
- 验证 Member 是有有效
- 验证 Interests 是否可用
- 验证 InterestsPackage 是否可用
- 验证 Member 是否拥有 InterestsPackage
- 验证最大单次消费金额
- 创建 InterestsPackage 快照 InterestsPackageSnapshot
- 更新 Interests 和 InterestsPackage 相关消费字段
- 创建 Interests 消费记录 InterestsRecord
- 保存相关对象
三层架构的实现方式
- 定义实体类 Interests、InterestsPackage
- 定义实体类对应的 Dao,比如 InterestsDao、InterestsPackageDao
- 定义 ConsumeInterestsService 类,实现业务逻辑
Entity
public class Member {
private Long memberID;
private String memberName;
private Integer status;
}
public class Interests {
private Long interestsID;
private Long interestsPackageID;
private Integer totalConsumeTimes;
private BigDecimal totalConsumeAmount;
private BigDecimal maxSingleConsumeAmount;
private Integer consumeTimes;
private BigDecimal consumeAmount;
}
public class InterestsPackage {
private Long interestsPackageID;
private Long memberID;
private Integer totalConsumeTimes;
private BigDecimal totalConsumeAmount;
private Integer consumeTimes;
private BigDecimal consumeAmount;
private DateTime effectDate;
private DateTime expireDate;
private Integer status;
}
public class InterestsPackageSnapshot {
private Long snapshotId;
private Long interestsPackageID;
private String packageInfo;
private Integer operationType;
}
public class InterestsRecord {
private Long recordID;
private Long orderID;
private Long memberID;
private Long interestsID;
private Long interestsPackageID;
private Integer recordType;
private BigDecimal consumeAmount;
private Integer consumeTimes;
private String remark;
}
Dao
public class MemberDao {
public Member get(Long memberID) {
return null;
}
}
public class InterestsDao {
public Interests get(Long interestsId){ return null; }
public void update(Interests interests){ }
}
public class InterestsPackageDao {
public InterestsPackage get(Long interestsPackageId) {
return null;
}
public void update(InterestsPackage interestsPackage) { }
}
public class InterestsPackageSnapshotDao {
public void insert(InterestsPackageSnapshot record) { }
}
public class InterestsRecordDao {
public void insert(InterestsRecord record) {}
}
Context
public class ConsumeInterestsContext {
private Long orderID;
private Long interestsID;
private Long memberID;
private BigDecimal consumeAmount;
}
Service
public class ConsumeInterestsServicePojoImpl implements ConsumeInterestsService {
private MemberDao memberDao;
private InterestsDao interestsDao;
private InterestsPackageDao interestsPackageDao;
private InterestsRecordDao interestsRecordDao;
private InterestsPackageSnapshotDao interestsPackageRecordDao;
public void service(ConsumeInterestsContext context) throws
MemberNotExistException,
MemberNotAvailableException,
InterestsNotExistException,
InterestsNotAvailableException,
InterestsPackageNotExistException,
InterestPackageNotBelongToMemberException,
InterestsPackageNotAvailableException {
// region 1、验证 Member 是有有效
Member member = this.memberDao.get(context.getMemberID());
if (member == null) {
throw new MemberNotExistException();
}
if (member.getStatus() != MemberStatusType.VALID.getId()) {
throw new MemberNotAvailableException();
}
// endregion
// region 2、验证 Interests 是否可用
Interests interests = interestsDao.get(context.getInterestsID());
if (interests == null) {
throw new InterestsNotExistException();
}
if (interests.getConsumeTimes() >= interests.getTotalConsumeTimes() ||
interests.getConsumeAmount().compareTo(interests.getTotalConsumeAmount()) >= 0) {
throw new InterestsNotAvailableException();
}
// endregion
// region 3、验证 InterestsPackage 是否可用
InterestsPackage interestsPackage = interestsPackageDao.get(interests.getInterestsPackageID());
if (interestsPackage == null) {
throw new InterestsPackageNotExistException();
}
if (interestsPackage.getStatus() != PackageStatusType.ACTIVATE.getId() ||
interestsPackage.getEffectDate().isAfterNow() || interestsPackage.getExpireDate().isBeforeNow() ||
interestsPackage.getConsumeTimes() >= interestsPackage.getTotalConsumeTimes() ||
interestsPackage.getConsumeAmount().compareTo(interestsPackage.getTotalConsumeAmount()) >= 0
) {
throw new InterestsPackageNotAvailableException();
}
// endregion
// region 4、验证 Member 是否拥有 InterestsPackage
if (!interestsPackage.getMemberID().equals(context.getMemberID())) {
throw new InterestPackageNotBelongToMemberException();
}
// endregion
// region 5、验证最大单次消费金额
BigDecimal actualConsumeAmount = context.getConsumeAmount();
if (actualConsumeAmount.compareTo(interests.getMaxSingleConsumeAmount()) > 0) {
actualConsumeAmount = interests.getMaxSingleConsumeAmount();
}
// endregion
// region 6、创建 InterestsPackage 快照 InterestsPackageSnapshot
InterestsPackageSnapshot interestsPackageSnapshot = new InterestsPackageSnapshot();
interestsPackageSnapshot.setInterestsPackageID(interestsPackage.getInterestsPackageID());
interestsPackageSnapshot.setOperationType(OperationType.CONSUME.getId());
interestsPackageSnapshot.setPackageInfo(JSON.toJSONString(interestsPackage));
// endregion
// region 7、更新 Interests 和 InterestsPackage 相关消费字段
interestsPackage.setConsumeTimes(interestsPackage.getConsumeTimes() + 1);
interestsPackage.setConsumeAmount(interestsPackage.getConsumeAmount().add(actualConsumeAmount));
interests.setConsumeTimes(interests.getConsumeTimes() + 1);
interests.setConsumeAmount(interests.getConsumeAmount().add(actualConsumeAmount));
// endregion
// region 8、创建 Interests 消费记录 InterestsRecord
InterestsRecord interestsRecord = new InterestsRecord();
interestsRecord.setOrderID(context.getOrderID());
interestsRecord.setMemberID(context.getMemberID());
interestsRecord.setInterestsID(interests.getInterestsID());
interestsRecord.setInterestsPackageID(interestsPackage.getInterestsPackageID());
interestsRecord.setRecordType(RecordType.CONSUME.getId());
interestsRecord.setConsumeAmount(actualConsumeAmount);
interestsRecord.setConsumeTimes(1);
interestsRecord.setRemark("xx consume amount at xxx");
// endregion
// region 9、保存相关对象
this.interestsDao.update(interests);
this.interestsPackageDao.update(interestsPackage);
this.interestsRecordDao.insert(interestsRecord);
this.interestsPackageRecordDao.insert(interestsPackageSnapshot);
// endregion
}
}
领域驱动设计实现方式

Service
public class ConsumeInterestsServiceDomainImpl implements ConsumeInterestsService {
private MemberRepository memberRepository;
private InterestsRepository interestsRepository;
private DomainEventPublisher eventPublisher;
public void service(ConsumeInterestsContext context) throws
MemberNotExistException,
MemberNotAvailableException,
InterestsNotExistException,
InterestsNotAvailableException,
InterestsPackageNotExistException,
InterestPackageNotBelongToMemberException,
InterestsPackageNotAvailableException {
Member member = this.memberRepository.get(context.getMemberID());
if (member == null) {
throw new MemberNotExistException();
}
if (!member.isAvailable()) {
throw new MemberNotAvailableException();
}
Interests interests = this.interestsRepository.get(context.getInterestsID());
if (interests == null) {
throw new InterestsNotExistException();
}
if (!interests.isAvailable()) {
throw new InterestsNotAvailableException();
}
InterestsPackage interestsPackage = interests.getInterestsPackage();
if (interestsPackage == null) {
throw new InterestsPackageNotExistException();
}
if (!interestsPackage.belongTo(context.getMemberID())) {
throw new InterestPackageNotBelongToMemberException();
}
if (!interestsPackage.isAvailable()) {
throw new InterestsPackageNotAvailableException();
}
interests.consume(context.getOrderID(), context.getConsumeAmount());
this.interestsRepository.update(interests);
this.eventPublisher.publish(new InterestsConsumedEvent(context.getInterestsID(), context.getConsumeAmount()));
}
}
哪些地方变了?
Entity
public class Member {
// region Fields
private Long memberID;
private String memberName;
private Integer status;
// endregion
// region Domain
public boolean isAvailable() {
return this.getStatus() != MemberStatusType.VALID.getId();
}
// endregion
}
public class Interests {
// region Fields
// endregion
// region Domain
private InterestsPackage interestsPackage;
private InterestsRecord currentRecord;
public InterestsPackage getInterestsPackage() {
return interestsPackage;
}
public void setInterestsPackage(InterestsPackage interestsPackage) {
this.interestsPackage = interestsPackage;
}
public InterestsRecord getCurrentRecord() {
return currentRecord;
}
public boolean isAvailable() {
return this.getConsumeTimes() < this.getTotalConsumeTimes() &&
this.getConsumeAmount().compareTo(this.getTotalConsumeAmount()) < 0;
}
protected BigDecimal getActualConsumeAmount(BigDecimal consumeAmount) {
if (consumeAmount.compareTo(this.getMaxSingleConsumeAmount()) > 0) {
return this.maxSingleConsumeAmount;
}
return consumeAmount;
}
public void consume(Long orderId, BigDecimal consumeAmount) {
BigDecimal actualConsumeAmount = this.getActualConsumeAmount(consumeAmount);
this.createRecord(RecordType.CONSUME, orderId, actualConsumeAmount);
this.setConsumeTimes(this.getConsumeTimes() + 1);
this.setConsumeAmount(this.getConsumeAmount().add(consumeAmount));
this.interestsPackage.backupSnapshot(OperationType.CONSUME);
this.interestsPackage.setConsumeTimes(interestsPackage.getConsumeTimes() + 1);
this.interestsPackage.setConsumeAmount(interestsPackage.getConsumeAmount().add(consumeAmount));
}
protected void createRecord(RecordType recordType, Long orderId, BigDecimal consumeAmount) {
InterestsRecord interestsRecord = new InterestsRecord();
interestsRecord.setOrderID(orderId);
interestsRecord.setMemberID(this.interestsPackage.getMemberID());
interestsRecord.setInterestsID(this.getInterestsID());
interestsRecord.setInterestsPackageID(this.interestsPackage.getInterestsPackageID());
interestsRecord.setRecordType(recordType.getId());
interestsRecord.setConsumeAmount(consumeAmount);
interestsRecord.setConsumeTimes(1);
interestsRecord.setRemark("xx consume amount at xxx");
this.currentRecord = interestsRecord;
}
// endregion
}
public class InterestsPackage {
// region Fields
// endregion
// region Domain
private InterestsPackageSnapshot snapshot;
public InterestsPackageSnapshot getSnapshot() {
return snapshot;
}
public boolean isAvailable() {
return this.status == PackageStatusType.ACTIVATE.getId() &&
this.getEffectDate().isBeforeNow() &&
this.getExpireDate().isAfterNow() &&
this.getConsumeTimes() < this.getTotalConsumeTimes() &&
this.getConsumeAmount().compareTo(this.getTotalConsumeAmount()) >= 0;
}
public boolean belongTo(long memberID){
return this.getMemberID().equals(memberID);
}
public void backupSnapshot(OperationType operationType) {
InterestsPackageSnapshot interestsPackageSnapshot = new InterestsPackageSnapshot();
interestsPackageSnapshot.setInterestsPackageID(this.getInterestsPackageID());
interestsPackageSnapshot.setOperationType(operationType.getId());
interestsPackageSnapshot.setPackageInfo(JSON.toJSONString(this));
this.snapshot = interestsPackageSnapshot;
}
// endregion
}
Repository
public class MemberRepository {
private MemberDao memberDao;
public Member get(Long memberId) {
return memberDao.get(memberId);
}
}
public class InterestsRepository {
private MemberDao memberDao;
private InterestsDao interestsDao;
private InterestsPackageDao interestsPackageDao;
private InterestsRecordDao interestsRecordDao;
private InterestsPackageSnapshotDao interestsPackageSnapshotDao;
public Interests get(Long interestsId) {
Interests interests = this.interestsDao.get(interestsId);
if (interests == null) {
return null;
}
InterestsPackage interestsPackage = this.interestsPackageDao.get(interests.getInterestsPackageID());
interests.setInterestsPackage(interestsPackage);
return interests;
}
public void update(Interests interests) {
this.interestsDao.update(interests);
this.interestsPackageDao.update(interests.getInterestsPackage());
this.interestsRecordDao.insert(interests.getCurrentRecord());
this.interestsPackageSnapshotDao.insert(interests.getInterestsPackage().getSnapshot());
}
}
public abstract class DomainEvent {
}
public class InterestsConsumedEvent extends DomainEvent {
private long memberID;
private long orderID;
public InterestsConsumedEvent(long interestsID, BigDecimal consumeAmount) {
this.memberID = memberID;
this.orderID = orderID;
}
}
public class DomainEventPublisher {
public void publish(DomainEvent event) {
}
}