代码之家  ›  专栏  ›  技术社区  ›  RobertPitt

方法链接的影响

  •  7
  • RobertPitt  · 技术社区  · 15 年前

    我知道在PHP中链接的好处,但是假设我们有以下情况

    $Mail = new MailClass("mail")
            ->SetFrom("X")
            ->SetTo("X")
            ->SetSubject("X")
            ->AddRecipient("X")
            ->AddRecipient("X")
            ->AddRecipient("X")
            ->AddRecipient("X")
            ->AddRecipient("X")
            ->AddRecipient("X")
            ->Send();
    

    反复返回和重用对象是否有任何问题,例如 速度 或未能遵守 最佳实践

    如果您的新到Fluent界面: Martin Fowler on Fluent-Interfaces

    我完全理解 以这种方式编程,并且可以这样处理:

    $Mail = new MailClass("mail");
    $Mail->AddRecipien(
        array(/*.....*/)
    );
    $Mail->SetFrom("X");
    $Mail->SetTo("X");
    $Mail->SetSubject("X");
    $Mail->Send();
    

    但是假设我有一个这样的物体:

    $Order = new Order()
             ->With(22,'TAL')
             ->With(38,'HPK')->Skippable()
             ->With(2,'LGV')
             ->Priority();
    

    注意 ->With(38,'HPK')->Skippable() ,这是此类编程的pro的完美示例。

    4 回复  |  直到 15 年前
        1
  •  5
  •   Hannes    15 年前

    如果你必须验证某件事,我认为验证它更有意义 在addRecipient方法本身中 但是性能应该差不多。我不知道使用方法链接的任何一般缺点。

        2
  •  2
  •   Mark Baker    15 年前

    不能直接从类实例化链接:

    $Mail = new MailClass("mail") 
                ->SetFrom("X")
                ->SetTo("Y");
    

    您必须先实例化,然后针对已实例化的对象链接:

    $Mail = new MailClass("mail") ;
    $Mail->SetFrom("X")
         ->SetTo("Y");
    

    如果在单独的setter方法中进行验证(如您应该的那样),则需要确保在遇到验证错误时抛出异常。不能简单地在出错时返回布尔值false,否则链接将尝试对布尔值而不是类实例调用下一个方法,然后您将得到。

    致命错误:调用成员函数 中非对象的setSubject()。 C:\xampp\htdocs\ochaintest.php在线 二十三

    如果抛出异常,可以将链包装在try中…抓住

    $Mail = new MailClass("mail");
    try {
        $Mail->SetFrom("X")
            ->SetTo("Y")
            ->SetSubject("Z");
    } catch (Exception $e) {
        echo $e->getMessage();
    }
    

    但作为警告,这将使实例处于部分更新状态,对于成功验证/执行的方法没有回滚(除非您自己编写一个回滚),并且不会调用异常后面的方法。

        3
  •  1
  •   Arc    15 年前

    编辑:更新答案以匹配问题
    函数调用比循环慢,例如链接 addRecipient() 与调用 addRecipients() 方法,它接受一个数组,然后在循环中处理该数组。

    此外,将更复杂的方法链接到Fluent API可能需要对与上一个调用方法相关的数据进行额外的簿记,以便下一个调用可以继续处理该数据,因为所有方法返回构建链的同一对象。 让我们看看您的示例:

    ...
    ->With(22, 'TAL')
    ->With(38, 'HPK')->Skippable()
    ->With(2, 'LGV')
    ...
    

    这需要你记住 Skippable() 将应用于 (38, 'HPK') 而不是 (22, 'TAL') .

    但是,您几乎不会注意到性能损失,除非您的代码在循环中被频繁调用,或者当您对Web服务器有如此多的并发请求,以致于它接近其极限时(对于重载网站就是这样)。

    另一个方面是方法链接模式强制使用异常来处理信号错误(我并不是说这是一件坏事,它只是不同于经典的“调用和检查函数结果”编码风格)。

    但是,通常会有一些函数产生其他值,而不是它们所属的对象(例如那些返回对象和访问器状态的函数)。 重要的是,API的用户可以在每次遇到新方法时,确定哪些函数是可链接的,哪些函数是不必参考文档的(例如,说明所有的mutator和只有mutator支持链接的准则)。


    回答原始问题:

    […]我对链接的问题是您不能真正执行额外的验证[…]

    或者,实现一个在设置所有属性后调用的专用验证方法,并让它返回一个验证失败数组(可以是纯字符串或对象,例如命名的 ValidationFailure )。

        4
  •  0
  •   Geekster    15 年前

    这是把双刃剑。

    好的一面?这比重新寻址类更干净,尽管它主要只是语法更改,但它会稍微加快处理速度。最好是循环这种类型的链,而不是循环长格式的每个调用。

    坏的一面?当人们第一次习惯它时,这将导致安全问题。在这个问题上,要努力净化传入的var,这样你就不会在那里传递一些你不应该传递的东西。不要把你的类弄得太复杂。

    1. 预先验证您的信息。
    2. 预先授权您的用户。

    我认为将这些方法链接到一个循环中没有问题,性能方面。