您还可以使用角色对象模式和良好的旧聚合。
不是拥有包含所有业务逻辑的智能实体,而是让它们变得愚蠢,然后将所有业务逻辑移动到聚合这些愚蠢实体的角色中。那么你的行为就是生活在角色中的一等公民。
例子:
interface BannableUser
{
public function ban();
}
具有一种特定行为的接口遵循接口隔离原则。它还极大地增加了重用的可能性,因为与具有特定于应用程序行为集合的实体相比,您更有可能重用单个行为。
现在要实现它,您需要创建一个适当的角色类:
class BannableUserRole implements BannableUser
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function ban()
{
$this->user->isBanned = true;
}
}
您仍然有一个 User 实体,但它已完全剥离了所有行为。它本质上只是一袋 Getter 和 Setter 或公共属性。它代表您的系统是什么。这是数据部分,而不是交互部分。交互现在在角色内部。
class User
{
public $isBanned;
// … more properties
}
现在假设您有某种 Web UI,您可以在控制器中执行以下操作:
class BanUserController implements RequestHandler
{
// …
public function handleRequest(Request $request)
{
$userId = $request->getVar('user_id');
$user = $this->userRepository->findById($userId);
$bannableUser = new BannableUserRole($user);
$bannableUser->ban();
}
}
您可以通过将用户的实际查找和角色分配移动到 UseCase 类中来进一步解耦。我们称之为上下文:
class BanUserContext implements Context
{
public function run($userId)
{
$user = $this->userRepository->findById($userId);
$bannableUser = new BannableUserRole($user);
$bannableUser->ban();
}
}
现在,您的模型层中的所有业务逻辑都与您的用户界面完全隔离。上下文是您的系统所做的。您的控制器只会委托给适当的上下文:
class BanUserController implements RequestHandler
{
// …
public function handleRequest(Request $request)
{
$this->banUserContext->run($request->getVar('user_id'));
}
}
就是这样。不需要 Runkit 或类似的黑客。以上是数据上下文交互架构模式的简化版本,以防您想进一步研究。