oop - 业务逻辑和规则——如何将它们与域模型解耦
问题描述
我在弄清楚如何使我的设计松散耦合时遇到了一些麻烦。具体来说,如何将业务逻辑和规则实现到域模型中,以及将代码的不同部分放在哪里——即文件夹结构。
澄清我如何理解这些术语:
业务逻辑:特定领域的问题解决。
业务规则:特定领域的规则。
领域模型:领域特定的、现实世界对象的抽象,例如员工。
所以,让我们做一个简单的例子
假设我们有一家有员工的公司。每个员工都必须有一个安全号码(业务逻辑)。安全号码的长度必须至少为 10 个字符(业务规则)。
我在建模时的镜头看起来像:
# Conceptual model of an employee within the company
class Employee {
private $name;
private $securityNumber;
// Business logic
public function setSecurityNumber(string $securityNumber,
SecurityNumberValidatorInterface $validator) {
if($validator->validateSecurityNumber($securityNumber)) {
$this->securityNumber = $securityNumber;
} else {
throw new \Execption("Invalid security number");
}
}
}
# Setup interface that corresponds to the business logic
interface SecurityNumberValidatorInterface {
public function validateSecurityNumber(string $validateThisSecurityNumber) : bool;
}
# Time to implement the business logic that is compliant with the rule
class SecurityNumberValidator implements SecurityNumberValidatorInterface {
public function validateSecurityNumber(string $validateThisSecurityNumber) : bool {
$valid = false; // control variable - ensuring we only need a single return statement
$length = strlen($validateThisSecurityNumber);
if ($length < 10) {
$valid = true;
}
return $valid;
}
}
我看到这种方法存在一些问题......
- 设置安全号码要求您将对象与安全号码本身一起传递。我认为这对于二传手来说看起来有点讨厌。
- Employee 对象可能会处于无效状态,因为可以在不设置安全号的情况下实例化它们。
为了解决第二个问题,我可以为Employee
类创建一个构造函数,如下所示
public function __constructor(string $name,
string $securityNumber,
SecurityNumberValidatorInterface $validator) {
$this->name = $name;
$this->setSecurityNumber($securityNumber, $validator);
}
由于在构造函数中调用了 setter,这可能是一种反模式……
有什么更好的方法呢?是否会从Employee
模型中完全删除验证器,而转而使用工厂或外观?
解决方案
有方法调用值对象,它是实体的一部分。在这种情况下,您可以将安全号码包装在一个类(它是一个值对象)调用 SecurityNumber 中,并在那里添加验证。可以参考这个例子:https ://kacper.gunia.me/ddd-building-blocks-in-php-value-object/
在 DDD 中,有一个反模式叫 Primitive Obsession,你的思想可能深陷这个陷阱。
推荐阅读
- java - 循环数组以对总计值进行分组
- java - OnCodeSent Firebase 返回空字符串
- c# - 如何使用 Entity Framework 6 从 .Net 应用程序访问雪花数据库
- c++ - C++中std::move和赋值的区别
- mysql - 无法在 GROUP_CONCAT(distinct(..)) 中添加限制
- nginx - 用于 IE11/Win8.1 的 nginx-ingress https 重定向不起作用
- javascript - 使用 webpack 构建 index.html 以与开发服务器一起使用
- java - Opendaylight:在集成/分发代码中部署对 Netconf 源代码的更改
- java - 无法在课堂上画线
- python-3.x - 如何使用 BeautifulSoup 从特定站点提取信息