Łuk*_*oda 6 php design-patterns
我有User实体.我想拥有这个实体的多个"类型",具有不同的经理和存储库.所有User类型的所有实体仅共享UserInterface.现在,我正在寻找一种组织一切的好方法.我想到的第一件事是创建这样的东西:
interface UserTypeManagerInterface
{
public function addUserType($name, RepositoryInterface $repository, ManagerInterface $manager);
public function hasType($name);
public function getRepository($type);
public function getManager($type);
}
Run Code Online (Sandbox Code Playgroud)
然后在我想要同时管理多种类型的User地方,我会注入这个,并且在我想管理特定类型用户的地方,我只能为其类型注入特定的存储库和管理器对象.
看起来像一个非常干净的方法,但同时,当我想使用UserTypeManager我需要模拟的类创建测试时UserTypeManager,那么这个模拟将需要返回其他模拟(存储库和管理器).
这当然是可行的,但它让我思考是否可以避免这种情况.我能想到的唯一另一件事就是允许在测试过程中避免上述复杂性,这样就像这样:
interface UserTypeManagerInterface {
public function addUserType($name, RepositoryInterface $repository, ManagerInterface $manager);
}
/**
* My class managing multiple types of user.
*/
class ManageMultipleTypesOfUsers implements UserTypeManagerInterface {
// ...
}
Run Code Online (Sandbox Code Playgroud)
所以我只想将所有存储库和管理器添加到实现UserTypeManagerInterface接口的所有类中.所以对象会直接使用给他们的东西.
这样测试会更加清晰,因为我只需要模拟一个管理器和一个存储库来测试类ManageMultipleTypesOfUsers,但这感觉太像过度工程了.;)
这里有任何中间地带吗?
我无法对此给出明确的答案,因为这是一种权衡。
据我所知 User 是一个纯值对象?这是一个好的开始。这意味着操作起来很简单,没有副作用。
现在,考虑这些会影响您的设计的变量:
delete(User $user)- 只允许管理员,其他实现只是抛出,基本权限检查)或使用截然不同的代码?那么,这些变量如何影响我们的决策呢?
由于我不知道要求是什么,所以我无法给你一个理想的解决方案。您提出的(第二个)解决方案适用于“过度设计”的情况。
更温和的解决方案是函数式方法:
function addAdminUser($name, RepositoryInterface $repository, ManagerInterface $manager) { /* ... */ }
function addNormalUser($name, RepositoryInterface $repository, ManagerInterface $manager) { /* ... */ }
// you even can pass this around as a callable ($cb = "addAdminUser"), or (pre-binding):
$cb = function($name) use ($repo, $mgr) { addAdminUser($name, $repo, $mgr); };
Run Code Online (Sandbox Code Playgroud)
或者从根本上来说(如果普通用户是管理员用户添加的子集)[只要函数本身没有副作用并且其调用者不会太难测试]:
function addUser($name, $type, RepositoryInterface $repository, ManagerInterface $manager) {
/* ... common logic ... */
if ($type == IS_ADMIN_USER) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
如果这太激进,也可以将回调注入 addUser:
function addUser($name, $cb, RepositoryInterface $repository, ManagerInterface $manager) {
$user = new User;
/* ... common logic ... */
$cb($user, $repository, $manager);
}
Run Code Online (Sandbox Code Playgroud)
是的,函数式方法可能不那么可测试(即,如果直接调用该函数(不作为可调用传递),您将无法模拟该函数),但它可能会给您带来可读性的巨大提升。保存琐碎间接的级别可能会使您的代码更易于分析。我强调的是可能,因为删除太多间接可能会达到相反的效果。找到适用于您的应用程序的中间立场。
TL;DR:PHP 为您提供了一种更实用的方法,但可测试性较差。有时这是一个很好的权衡,有时则不是。这取决于您的具体代码,中间立场在哪里。
Ps:在你的第二个提案中,唯一让我觉得有点RepositoryInterface $repository, ManagerInterface $manager味道的是 addUserType 方法签名。您确定它不是构造函数的一部分吗?
| 归档时间: |
|
| 查看次数: |
746 次 |
| 最近记录: |