早上好
我已经读过很多次了,在AR中应该避免使用setter和getter。虽然我可以理解安装者的原因,但对于那些明显属于企业的吸气剂,我有些不同意。
让我们想象以下 User AR:
namespace vendor\Domain\Model;
class User
{
private $userId;
private $username;
private $password;
private $email;
static public register(...): User { ... } // Ubiquitous Language
public function unregister(...) { ... } // Ubiquitous Language
public function changePassword(...) { ... } // Ubiquitous Language
public function changeEmail(...) { ... } // Ubiquitous Language
public function getAggregateId(): UserId { ... } // A getter
public function getUsername(): UserName { ... } // A getter
public function getEmail(): UserEmail { ... } // A getter
...
}
现在让我们想象以下 UserRepository 界面:
namespace vendor\Domain;
interface UserRepository
{
public function userOfId(UserId $userId):? User;
public function userOfname(UserName $userName):? User;
public function userOfEmail(UserEmail $userEmail):? User;
...
}
基本上在这里,我有一些查找器,通过它的ID,用户名或电子邮件地址可以检索用户。
现在,让我们想象一下该 UserRepository 的以下内存中实现:
namespace vendor\Infrastructure\Persistence;
use vendor\Domain\UserRepository;
class InMemoryUserRepository implements UserRepository
{
/** User[] */
private $users;
public function userOfId(UserId $userId):? User
{
if(!isset($this->users[$userId->tostring()]) {
return null;
}
$this->users[$userId->tostring()];
}
public function userOfEmail(UserEmail $userEmail):? User
{
foreach($users as $user) {
if($user->getEmail()->sameValueAs($userEmail) {
return $user;
}
}
return null;
}
...
}
如您所见,在该内存实现中,我需要通过电子邮件过滤用户,并访问其电子邮件属性。这必然意味着用户 AR需要提供 getEmail() getter。真的不好吗?允许具有必须访问的属性的吸气剂?我是否应该简单地认为 getEmail()吸气剂具有商业意义,在这种情况下,它是完全有效的吗?
答案 0 :(得分:2)
凯特很好。 “不要写吸气剂”的情况是为了避免将内部状态暴露在聚合之外:当您的服务采用聚合时,获取其状态并基于此做出一些决定。那就是你要避免的事情。
您可以遵循Demeter法则的指南,并为此而努力。不要严格避免使用吸气剂,但要注意它们。
拥有getId
或getUsername
很好。
没有getCollection
类方法可返回可变集合。总体上失去了对内部细节,实施细节的控制。当暴露类似getFriends()
之类的东西时,您的服务可以调用它,在聚合之外添加或删除东西,并且您基本上失去了重构聚合而不破坏所有内容的能力。在这种情况下,addFriend()
和deleteFriend()
可以解决。而且,如果getFriends()
返回一个不可变集合,那也很好。
不要写吸气剂并不是硬性规定,不要在集合之外暴露过多的状态,但是不要因没有任何吸气剂。合理使用它们。