领域模型设计为复杂问题的解决提供了一套方法,但其理论往往非常抽象,本系列文单旨在提供一些最佳实践。您需要首先认识到,软件的设计过程主观性很强,我希望能够提供一个设计思想让您在入门中有一个感性的认识,莫要陷入到“教条主义”中。
领域驱动设计:强调的是战略,是宏观的,它为复杂业务的解决提供了指导思想。在实践中,无论是“面向过程”还是“面向对象”的设计方式,都是领域驱动思路的一种实现方式,要根据不同的场景使用不同的方式,请您不要陷入自我怀疑,否认“面向过程”。
程序研发过程中,往往涉及到验证。不论是采用哪种实现方式(面向过程的方式或者对象驱动),原则上,公有方法中的第一件事情是验证参数。何时,何地,如何做验证是一个开发者要面临的挑战。做一个合格的软件设计师(在这里,我喜欢用设计师而非码农或程序员,那是对于自己的不尊重),当您想要写一份干净、整洁及可读性很强的代码时,细节上的转变会让您的作品看起来更加赏心悦目、更有自信、代码可维护性更强。
代码是给人看的,不是机器
软件设计不存在固定的规则,如果您在开发过程始终坚持某些原则就产生了规则
1、基于视图模型的验证
在展开书写之前,我们需要假设一个非常简单的业务场景:用户的每一个操作,都需要为其增加一个操作日志。在此处,我们遵循如下设计原则:1)涉及新建、更新、复杂查询业务时,Service层公有方法都接收视图模型作为参数,而非拆成一个个独立的参数;2)所有公有方法的要做的第一件事是验证。视图模型代码如下。
public class OperationLogInfo {
private String module;
private String operatorId;
private String operatorName;
private String action;
public String getModule() {
return module;
}
public void setModule(String module) {
this.module = module;
}
public String getOperatorId() {
return operatorId;
}
public void setOperatorId(String operatorId) {
this.operatorId = operatorId;
}
public String getOperatorName() {
return operatorName;
}
public void setOperatorName(String operatorName) {
this.operatorName = operatorName;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
接下来为Service层代码。
@Service
public class OperationLogService {
private static Logger logger = LoggerFactory.getLogger(OperationLogService.class);
/**
* 保存操作日志
* @param operationLogInfo 操作日志信息
*/
public void save(OperationLogInfo operationLogInfo) {
try {
if (operationLogInfo == null) {
throw new IllegalArgumentException(OperationMessages.NO_OPERATION_LOG);
}
if (StringUtils.isEmpty(operationLogInfo.getModule())) {
throw new IllegalArgumentException(OperationMessages.NO_MODULE_INFO);
}
if (StringUtils.isEmpty(operationLogInfo.getOperatorId())) {
throw new IllegalArgumentException(OperationMessages.NO_OPERATOR_ID_TYPE);
}
if (StringUtils.isEmpty(operationLogInfo.getOperatorName())) {
throw new IllegalArgumentException(OperationMessages.NO_OPERATOR_NAME_TYPE);
}
if (StringUtils.isEmpty(operationLogInfo.getAction())) {
throw new IllegalArgumentException(OperationMessages.NO_ACTION_TYPE);
}
OperationLogDataEntity entity = OperationLogDataEntity.of(operationLogInfo);
this.operationLogDao.save(entity);
} catch (IllegalArgumentException e) {
logger.error(e.getMessage(), e);
} catch (Exception e) {
logger.error(OperationMessages.SAVE_LOG_FAILED, e);
}
}
}
为了保持代码的干净,我引入了一个新的类”OperationMessages“,将所有的”报错信息“或者”操作提示“以静态常量的形式保存在一个统一的地方供后续代码引用。如果您的服务中有多个包,建议为每一个包中都加入这样一个包含常量的类,用于区分不同业务的操作提示。下面为这个常量的代码片段。
/**
* 操作提示
*/
final public class OperationMessages {
public static final String NO_OPERATION_LOG = "无操作日志信息";
}