89人参与 • 2024-08-04 • 架构设计
银行账户转账案例是一个经典的领域驱动设计(ddd)应用场景。
接下来我们通过一个简单的银行账户转账案例,来了解如何使用 wow 进行领域驱动设计以及服务开发。
模块 | 说明 |
---|---|
example-transfer-api | api 层,定义聚合命令(command)、领域事件(domain event)以及查询视图模型(query view model),这个模块充当了各个模块之间通信的“发布语言”。 |
example-transfer-domain | 领域层,包含聚合根和业务约束的实现。聚合根:领域模型的入口点,负责协调领域对象的操作。业务约束:包括验证规则、领域事件的处理等。 |
example-transfer-server | 宿主服务,应用程序的启动点。负责整合其他模块,并提供应用程序的入口。涉及配置依赖项、连接数据库、启动 api 服务 |
状态聚合根(accountstate
)与命令聚合根(account
)分离设计保证了在执行命令过程中,不会修改状态聚合根的状态。
accountstate
)建模public class accountstate implements identifier {
private final string id;
private string name;
/**
* 余额
*/
private long balanceamount = 0l;
/**
* 已锁定金额
*/
private long lockedamount = 0l;
/**
* 账号已冻结标记
*/
private boolean frozen = false;
@jsoncreator
public accountstate(@jsonproperty("id") string id) {
this.id = id;
}
@notnull
@override
public string getid() {
return id;
}
public string getname() {
return name;
}
public long getbalanceamount() {
return balanceamount;
}
public long getlockedamount() {
return lockedamount;
}
public boolean isfrozen() {
return frozen;
}
void onsourcing(accountcreated accountcreated) {
this.name = accountcreated.name();
this.balanceamount = accountcreated.balance();
}
void onsourcing(amountlocked amountlocked) {
balanceamount = balanceamount - amountlocked.amount();
lockedamount = lockedamount + amountlocked.amount();
}
void onsourcing(amountentered amountentered) {
balanceamount = balanceamount + amountentered.amount();
}
void onsourcing(confirmed confirmed) {
lockedamount = lockedamount - confirmed.amount();
}
void onsourcing(amountunlocked amountunlocked) {
lockedamount = lockedamount - amountunlocked.amount();
balanceamount = balanceamount + amountunlocked.amount();
}
void onsourcing(accountfrozen accountfrozen) {
this.frozen = true;
}
}
account
)建模@statictenantid
@aggregateroot
public class account {
private final accountstate state;
public account(accountstate state) {
this.state = state;
}
accountcreated oncommand(createaccount createaccount) {
return new accountcreated(createaccount.name(), createaccount.balance());
}
@oncommand(returns = {amountlocked.class, prepared.class})
list<?> oncommand(prepare prepare) {
checkbalance(prepare.amount());
return list.of(new amountlocked(prepare.amount()), new prepared(prepare.to(), prepare.amount()));
}
private void checkbalance(long amount) {
if (state.isfrozen()) {
throw new illegalstateexception("账号已冻结无法转账.");
}
if (state.getbalanceamount() < amount) {
throw new illegalstateexception("账号余额不足.");
}
}
object oncommand(entry entry) {
if (state.isfrozen()) {
return new entryfailed(entry.sourceid(), entry.amount());
}
return new amountentered(entry.sourceid(), entry.amount());
}
confirmed oncommand(confirm confirm) {
return new confirmed(confirm.amount());
}
amountunlocked oncommand(unlockamount unlockamount) {
return new amountunlocked(unlockamount.amount());
}
accountfrozen oncommand(freezeaccount freezeaccount) {
return new accountfrozen(freezeaccount.reason());
}
}
transfersaga
)转账流程管理器(transfersaga
)负责协调处理转账的事件,并生成相应的命令。
onevent(prepared)
: 订阅转账已准备就绪事件(prepared
),并生成入账命令(entry
)。onevent(amountentered)
: 订阅转账已入账事件(amountentered
),并生成确认转账命令(confirm
)。onevent(entryfailed)
: 订阅转账入账失败事件(entryfailed
),并生成解锁金额命令(unlockamount
)。@statelesssaga
public class transfersaga {
entry onevent(prepared prepared, aggregateid aggregateid) {
return new entry(prepared.to(), aggregateid.getid(), prepared.amount());
}
confirm onevent(amountentered amountentered) {
return new confirm(amountentered.sourceid(), amountentered.amount());
}
unlockamount onevent(entryfailed entryfailed) {
return new unlockamount(entryfailed.sourceid(), entryfailed.amount());
}
}
internal class accountktest {
@test
fun createaccount() {
aggregateverifier<account, accountstate>()
.given()
.`when`(createaccount("name", 100))
.expecteventtype(accountcreated::class.java)
.expectstate {
assertthat(it.name, equalto("name"))
assertthat(it.balanceamount, equalto(100))
}
.verify()
}
}
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论