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



我是一名PHP开发人员,目前正在使用Symfony2。

我想提出我的问题如下:

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

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

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

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

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

创建通用接口:

interface Validatable 
{
public function isValid(): bool;
}

创建一个特征来实现常见行为:

trait HasStatus 
{
/**
* @var int
* @ORMColumn(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());
}

为什么我们需要接口?从技术上讲,我们不需要它,但我喜欢包含它,因为它允许使用通用的"可验证"类型提示来引用用户、客户、商家,并且它在代码中传达了您的意图。

搞砸了这不是一个好主意,实体具有状态值,并且 setter/getter 应该在实体文件声明中。 我理解 DRY 原理,但在这个层面上这样做......恕我直言,这不是一个好主意。

但是,如果您确定它们都具有状态,请在单独的文件中使用特征:

trait CheckStatusTrait{
return $this->status;
}

您只需将特征添加到您的类中:

class User {
use CheckStatusTrait
}

对于这种简单的代码,可以在每个实体中保留重复项,您可以添加一个带有"isValid"的接口,以便在必要时从外部将它们视为相同。

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

你也可以做同样的事情,不注入 StatusValidator 但询问 StatusValidator 带有 getStatusInterface 的 obejct 是否有效。

感谢大家的支持。我还使用 trait 来解决代码重复问题。但是,我看到这种特质似乎不是一个完美的特质。我不得不在下面遇到缺点:

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

以上是我的愿景。我只是试图找到更好的方法来解决这个问题。我希望它对每个人都有用。我听说过ValueObject,但显然并不真正理解它。我会试着弄清楚的!

最新更新