我可以使用哪些编码或设计模式来强制执行所需的方法调用序列?

What coding or design patterns can I use to enforce a required sequence of method calls?

我写了下面几行代码:

$this->validate($group);

$this->em->persist($group);
$this->em->flush();

如果 $group 无效,方法 "validate" 将抛出异常。问题是,它似乎有点 "fragile"。如果另一个开发人员更改了这段代码,他可能会不小心移动了验证方法,实体管理器会在不验证的情况下将对象保存到数据库中。

您认为下面几行代码更好还是我想多了?

$validGroup = $this->validate($group);

$this->em->persist($validGroup);
$this->em->flush();

是否有验证模式?

我会在 persist 内部进行验证,这样就不可能持久化未验证的对象。如果 em 是第三方代码并且您不想更改它,请将 em 包装在您自己的对象中,该对象在写入数据库之前进行验证并在任何地方使用它。

有几个选项可用于设计 em 或您的包装器,这样您只需编写一次,就可以在程序的任何地方使用单个实例。你可以

  • 赋予被持久化的对象验证自身的责任,例如要求所有持久对象都有一个 is_valid 方法。 em 或您的包装器会要求对象验证自身并在对象无效时抛出异常。如果您能够向持久对象添加行为,这可能是最好的解决方案,因为它将有效性的概念与数据放在同一位置。

  • em 或您的包装器检测对象的类型,查找(在注册表中或通过命名约定)知道如何验证该类型对象的验证器对象,要求验证器验证被持久化的对象,如果对象无效,再次抛出异常。这更复杂,但如果验证复杂到足以值得一个单独的对象,或者如果您不能向持久对象添加行为则有必要,这可能会有所帮助。

这个问题涉及到界面设计中一个很重要很有意义的问题。问题是 "undeclared ordering" 即方法调用的顺序是隐式的和未声明的。它是许多问题和混乱的根源。

有两种重构方法(至少)。上面都已经给出了,我只是总结一下。

  1. 使用一个方法调用的结果作为另一个调用的输入(就像 OP 已经做的那样)。这样可以保证秩序。当第一个方法调用的结果被多次使用时,它是适用和有用的。
  2. 在第二个方法中调用第一个方法(反之亦然)。这也将解决问题,因为界面的用户必须调用单个方法。

Template Pattern 适合这个问题。

在模板模式中,抽象 class 公开定义的方式/模板来执行其方法。它的 subclasses 可以根据需要重写方法实现,但是 调用的方式与抽象 class[=20= 定义的方式相同]。此模式属于行为模式类别。

abstract class MyTemplate{
   void myPersist(){
      validate();
      persist();
      flush();
}