我应该使用哪种设计模式将常用方法包装到实体中?

时间:2017-09-08 11:02:42

标签: php symfony design-patterns

我是一名PHP开发人员,目前我正在与Symfony2合作。

我想提出以下问题:

  • 我有4个实体:用户,帐户,客户,商家。他们都有地位。
  • 我想为他们构建一个名为'isValid'的常用方法,但不想修改他们的代码。
  • 方法逻辑很简单

    <!-- language: php -->
    public function isValid()
    {
        return self::STATUS_ACTIVE == $this->status;
    }
    
  • 通过将它们分开并在它与实体之间应用HAS-A关系,我认为它将更灵活和可维护。我不需要将代码复制到任何需要它的实体,即使将来也是如此。

如果您有经验。你能帮我为这种情况选择合适的模式吗?

4 个答案:

答案 0 :(得分:1)

在这些实体之间创建一个has-a关系是没有意义的,因为它们不相关。

然而,代码重复几乎从不合理。我会通过创建一个公共接口来解决它(User是一个可验证的实体,Customer是一个可验证的实体)并制作一个特征来封装常见的行为。

创建通用界面:

interface Validatable 
{

    public function isValid(): bool;

}

创建特征以实现常见行为:

trait HasStatus 
{

    /**
     * @var int
     * @ORM\Column(type="integer")
     */
    private $status;

    public function isValid(): bool
    {
        return $this->status === EntityStatus::STATUS_ACTIVE;
    }

}

让您的实体实现新界面并使用特征来避免重复:

class User implements Validatable {
    use HasStatus;

}

并使用它:

/** @var Validatable[] $validatables */
$validatables = [new User(), new Merchant(), new Customer()];

foreach ($validatables as $validatable) {
    var_dump($validatable->isValid());
}

为什么我们需要界面?从技术上讲,我们不需要它,但我喜欢包含它,因为它允许引用用户,客户,商家与共同的&#34; Validatable&#34; typehint 它在代码中传达了你的意图。

答案 1 :(得分:0)

弄乱这个并不是一个好主意,实体有状态值,而setter / getter应该在实体文件声明中。 我理解DRY原则,但在这个级别上做...这是恕我直言,不是一个好主意。

但如果您确定所有人都有状态,那么在单独的文件中使用特征:

trait CheckStatusTrait{
    return $this->status;
}

您只需将特质添加到您的课程中:

class User {
   use CheckStatusTrait
}

答案 2 :(得分:0)

对于那种简单的代码,可以将它留在每个实体中重复,你可以添加一个带有“isValid”的接口,以便在必要时从外部对待它们。

也许你的代码检查验证会变得更复杂,有一个负责的类是有意义的。 然后你可以创建一个StatusValidator类来检查给定对象的状态是否有效。为这种对象添加一个接口是有意义的,它有一个“getStatus”方法,比如说“getStatusInterface”。之后,您可以注入StatusValidator并在isValid方法中使用它。因为您的对象是实体,所以您需要使用doctrine的postLoad事件来注入StatusValidator。

您也可以通过不注入StatusValidator来执行相同的复杂操作,但是如果具有getStatusInterface的obejct是有效的,请询问StatusValidator。

答案 3 :(得分:0)

感谢大家的支持。我也使用trait来解决代码重复问题。但是,我发现这种特质似乎并不完美。我不得不承认以下缺点:

  • 将这个字段隐藏在特质中会让实体变得神秘莫测。实际上,不仅状态字段在许多实体上都可用,而且还有updatedDate,createdDate,type ...当类使用许多特征时,它看起来也很混乱。
  • 在开发期之后,该特征收集的方法越来越多,例如。 StatusTrait可以有isValid,hasStatus,setStatusDefault。但并非所有实体都使用它们。我的意思是一些实体使用isValid,一些使用setStatusDefault ..,所以我们将在traits中有更多的混合方法。在本期中,我认为如果我可以实现一个HAS-A关系类,我可以在实体需要时在运行时轻松设置它们。
  • 通过使用trait,实体类被修改,而不是扩展。在OOP设计中,这不是一个好习惯。实体类与数据库表的引用不一致。老实说,我更喜欢在实体类之外构建逻辑方法。

以上是我的愿景。我只是试图找到一种更好的方法来实现这个问题。我希望它对每个人都有用。我听说过ValueObject,但显然不是很明白。我会试着想出来的!