Welcome to pay attention to the public account “JAVA Front” to view more wonderful sharing articles, mainly including source code analysis, practical application, architecture thinking, workplace sharing, product thinking and so on, at the same time, welcome to add my wechat “JAVA_front” to communicate and learn together
1 DDD
Recently, I have been driving design in the learning field, and I have also learned COLA code and carried out some project practices. COLA code is neat and elegant, but there are certain learning costs and use costs. Finally, an engineering idea was to be implemented. I integrated some DDD technical frameworks, deleted CQRS and event bus mode, and sorted out a simple, practical and easy to implement project architecture.
(1) demo-infrastructure
Base layer. Include basic functions, such as database access, cache access, message sending, and a common toolkit
(2) demo-dependency
External access layer. In this module, the external RPC service is invoked to parse the return code and return data
(3) demo-domain
The domain layer. This module contains the BO (Business Object) similar to the three-tier architecture, but the difference is that it is defined using the congestion pattern, so the domain layer itself also contains the Business logic, rather than simply attribute declarations
(4) demo-service
The business layer. Although both the domain layer and the business layer contain businesses, they serve different purposes. Compared with the domain layer, the business layer can combine services of different domains and add flow control, monitoring, logging, and permission control facets
(5) demo-api
External interface layer. Provides externally oriented interface declarations
(6) demo-controller
External access layer. Provides externally oriented access points
2. Three-tier architecture and anaemic model
Before using the above framework, we generally used a three-tier architecture for business development:
Repository + Entity Service + BO (Business Object) Controller + VO (View Object)Copy the code
In three-tier architecture business development, anaemic model-based development is often used. An anaemic model is one in which the business logic is all in the Service layer and the business objects contain only the data but not the business logic. Let’s examine the code example.
/** * Account business object **@authorWechat official account "JAVA Front" * */
public class AccountBO {
/** * Account ID */
private String accountId;
/** * Account balance */
private Long balance;
/** * Whether to freeze */
private boolean isFrozen;
public String getAccountId(a) {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public Long getBalance(a) {
return balance;
}
public void setBalance(Long balance) {
this.balance = balance;
}
public boolean isFrozen(a) {
return isFrozen;
}
public void setFrozen(boolean isFrozen) {
this.isFrozen = isFrozen; }}/** ** Transfer service implementation **@authorWechat official account "JAVA Front" * */
@Service
public class TransferServiceImpl implements TransferService {
@Autowired
private AccountService accountService;
@Override
public boolean transfer(String fromAccountId, String toAccountId, Long amount) {
AccountBO fromAccount = accountService.getAccountById(fromAccountId);
AccountBO toAccount = accountService.getAccountById(toAccountId);
/** Check the transfer account **/
if (fromAccount.isFrozen()) {
throw new MyBizException(ErrorCodeBiz.ACCOUNT_FROZEN);
}
if (fromAccount.getBalance() < amount) {
throw new MyBizException(ErrorCodeBiz.INSUFFICIENT_BALANCE);
}
fromAccount.setBalance(fromAccount.getBalance() - amount);
/** Check the transfer account **/
if (toAccount.isFrozen()) {
throw new MyBizException(ErrorCodeBiz.ACCOUNT_FROZEN);
}
toAccount.setBalance(toAccount.getBalance() + amount);
/** Update database **/
accountService.updateAccount(fromAccount);
accountService.updateAccount(toAccount);
returnBoolean.TRUE; }}Copy the code
The TransferServiceImpl implementation class is anaemic model development, where AccountBO has only data and no business logic. The entire code style tends to be process-oriented, which is why some people call anemic models anti-patterns.
3. Hyperemia model
3.1 instance a
We introduced Domain layer in the congestion model based DDD development pattern. The Domain layer contains the business object BO, but not just the data. This layer also contains the business logic. Let’s examine the code example.
/** * Account business object **@authorWechat official account "JAVA Front" * */
public class AccountBO {
/** * Account ID */
private String accountId;
/** * Account balance */
private Long balance;
/** * Whether to freeze */
private boolean isFrozen;
/**
* 出借策略
*/
private DebitPolicy debitPolicy;
/** ** entry strategy */
private CreditPolicy creditPolicy;
/** * lending method **@paramThe amount amount * /
public void debit(Long amount) {
debitPolicy.preDebit(this, amount);
this.balance -= amount;
debitPolicy.afterDebit(this, amount);
}
/** * enter method **@paramThe amount amount * /
public void credit(Long amount) {
creditPolicy.preCredit(this, amount);
this.balance += amount;
creditPolicy.afterCredit(this, amount);
}
public boolean isFrozen(a) {
return isFrozen;
}
public void setFrozen(boolean isFrozen) {
this.isFrozen = isFrozen;
}
public String getAccountId(a) {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public Long getBalance(a) {
return balance;
}
/** * BO and DO conversions must have a set method
public void setBalance(Long balance) {
this.balance = balance;
}
public DebitPolicy getDebitPolicy(a) {
return debitPolicy;
}
public void setDebitPolicy(DebitPolicy debitPolicy) {
this.debitPolicy = debitPolicy;
}
public CreditPolicy getCreditPolicy(a) {
return creditPolicy;
}
public void setCreditPolicy(CreditPolicy creditPolicy) {
this.creditPolicy = creditPolicy; }}/** * The entry policy implements **@authorWechat official account "JAVA Front" * */
@Service
public class CreditPolicyImpl implements CreditPolicy {
@Override
public void preCredit(AccountBO account, Long amount) {
if (account.isFrozen()) {
throw newMyBizException(ErrorCodeBiz.ACCOUNT_FROZEN); }}@Override
public void afterCredit(AccountBO account, Long amount) {
System.out.println("afterCredit"); }}/** * The lending policy implements **@authorWechat official account "JAVA Front" * */
@Service
public class DebitPolicyImpl implements DebitPolicy {
@Override
public void preDebit(AccountBO account, Long amount) {
if (account.isFrozen()) {
throw new MyBizException(ErrorCodeBiz.ACCOUNT_FROZEN);
}
if (account.getBalance() < amount) {
throw newMyBizException(ErrorCodeBiz.INSUFFICIENT_BALANCE); }}@Override
public void afterDebit(AccountBO account, Long amount) {
System.out.println("afterDebit"); }}/** ** Transfer service implementation **@authorWechat official account "JAVA Front" * */
@Service
public class TransferServiceImpl implements TransferService {
@Resource
private AccountService accountService;
@Resource
private CreditPolicy creditPolicy;
@Resource
private DebitPolicy debitPolicy;
@Override
public boolean transfer(String fromAccountId, String toAccountId, Long amount) {
AccountBO fromAccount = accountService.getAccountById(fromAccountId);
AccountBO toAccount = accountService.getAccountById(toAccountId);
fromAccount.setDebitPolicy(debitPolicy);
toAccount.setCreditPolicy(creditPolicy);
fromAccount.debit(amount);
toAccount.credit(amount);
accountService.updateAccount(fromAccount);
accountService.updateAccount(toAccount);
returnBoolean.TRUE; }}Copy the code
AccountBO contains a policy object that implements business logic. In this way, the business logic is implemented in the policy object, reducing the code to the process at the service level and making the code structure more cohesive.
3.2 instance 2
We also analyze an example of a cohesive congestion model that will verify logic.
/** * validator **@authorWechat official account "JAVA Front" * */
public interface BizValidator {
BizValidateResult validate(a);
}
/** * Check result **@authorWechat official account "JAVA Front" * */
public class BizValidateResult {
private boolean isSuccess;
private String message;
public BizValidateResult(boolean isSuccess, String message) {
super(a);this.isSuccess = isSuccess;
this.message = message;
}
public boolean isSuccess(a) {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
public String getMessage(a) {
return message;
}
public void setMessage(String message) {
this.message = message; }}/** * Commodity business object **@authorWechat official account "JAVA Front" * */
public class GoodsBO implements BizValidator {
private String goodsId;
private String goodsName;
private GoodsService goodsService;
public String getGoodsId(a) {
return goodsId;
}
public void setGoodsId(String goodsId) {
this.goodsId = goodsId;
}
public String getGoodsName(a) {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public GoodsService getGoodsService(a) {
return goodsService;
}
public void setGoodsService(GoodsService goodsService) {
this.goodsService = goodsService;
}
@Override
public BizValidateResult validate(a) {
if(StringUtils.isEmpty(goodsId)) {
throw new MyBizException(ErrorCodeBiz.ILLEGAL_ARGUMENT);
}
if(StringUtils.isEmpty(goodsName)) {
throw new MyBizException(ErrorCodeBiz.ILLEGAL_ARGUMENT);
}
Integer stock = goodsService.getGoodsStock(goodsId);
if(stock <= 0) {
throw new MyBizException(ErrorCodeBiz.NO_STOCK);
}
return new BizValidateResult(Boolean.TRUE, null); }}/** * order service implementation **@authorWechat official account "JAVA Front" * */
@Service
public class OrderServiceImpl implements OrderService {
@Resource
private GoodsService goodsService;
@Override
public String createOrder(GoodsBO goods) {
if(null == goods) {
throw new MyBizException(ErrorCodeBiz.ILLEGAL_ARGUMENT);
}
goods.setGoodsService(goodsService);
goods.validate();
System.out.println("Create order");
return "orderId_111"; }}Copy the code
4 Some thoughts
One could argue that congestion just puts some business in the Domain layer, nothing special. I have the following reflections on this view:
(1) The code business style becomes more object-oriented rather than procedural, and the overall logic becomes more cohesive
(2) There is an open and closed principle in the design principle: open for expansion, closed for modification. I think this is the most important design principle. Many design patterns, such as strategy mode and template method mode, are designed based on this principle. The congestion model BO can contain various policies that can be managed using policy patterns
(3) Domain layer is not to replace Service layer, but a kind of supplementary enhancement, although Domain layer and business layer contain business but different purposes. Compared with the domain layer, the business layer can combine services of different domains and add flow control, monitoring, logging, and permission control facets
(4) The Lombok framework is very popular now, making code very concise. One caveat is that arbitrary use of Lombok can break code encapsulation, such as the fact that an AccountBO object should not expose the setBalance method. But it is also a tradeoff strategy because layer objects that require property copies must expose the setBalance method
Welcome to pay attention to the public account “JAVA Front” to view more wonderful sharing articles, mainly including source code analysis, practical application, architecture thinking, workplace sharing, product thinking and so on, at the same time, welcome to add my wechat “JAVA_front” to communicate and learn together