【问题标题】:"Early return" best practice and DRY“早退”最佳实践和DRY
【发布时间】:2017-05-10 18:53:33
【问题描述】:

我想知道在某些情况下是否有更好的方法来“摆脱”方法。让我用代码更好地解释一下:

function execute($context)
{
    // some init actions

    $event = new BeforeOperationOne();
    $this->dispatch($event);
    if ($event->accessGranted()) {
        $context->setUser($this->user);
        // other repeated code

        return;
    }

    $result = $this->operationOne();

    // some other code

    $event = new BeforeOperationTwo();
    $this->dispatch($event);
    if ($event->accessGranted()) {
        $context->setUser($this->user);
        // other repeated code

        return;
    }

    // this is not important what is access checker, 
    // this is just to show that all following code uses data
    // computed in previous steps
    $accessChecker = new AccessChecker($result);
    $this->operationTwo(accessChecker);

    // some other code

    $event = new BeforeOperationThree();
    $this->dispatch($event);
    if ($event->accessGranted()) {
        $context->setUser($this->user);
        // other repeated code

        return;
    }

    $this->operationThree();

    // some other code
}

我们在这里重复了这个条件,当用户可以从事件访问时,在上下文中设置用户。我能想到的选择是:

  1. 丑陋的 do-while(false) 或 goto(我最好保持现在这样)
  2. 将此提取到方法并将条件更改为 if (!$this->handleEvent($event, $context)) { return; }- 这没有多大帮助,并且无法认为更好的名称句柄不会说它正在返回一些东西
  3. 为操作构建闭包数组并循环检查。我们可以假设所有事件类都派生自具有 accessGranted 方法的公共类。这可能很难看,因为某些操作需要来自先前“步骤”的数据,我必须将它们保留在外面并传递它们。
  4. 抛出并捕获用户有权访问的异常 - 另一个糟糕的解决方案。

你有什么想法可以写得更好吗?

【问题讨论】:

  • 您的问题将收到很多基于意见的答案。但是,请查看 Object CalisthenicsSOLID 和 Clean Code book - 第 3 章 - Functions。
  • 最后,正确的词是“early return
  • 也许“责任链”模式会有用?
  • 我真正想做的是提供使用事件系统挂钩方法的可能性,以及是否可以提前完成方法以避免对用户访问进行不必要的繁重计算。

标签: php dry


【解决方案1】:

@Greg 我正在考虑类似的事情:

abstract class Handler
{
    protected $nextHandler = null;

    abstract public function Request($request);

    public function setNextHandler(Handler $handler)
    {
        $this->nextHandler = $handler;
    }

    protected function someOperations($event)
    {
        //i copied this section, so you must shape that
        $this->dispatch($event);
        if ($event->accessGranted()) {
            $context->setUser($this->user);
            // other repeated code

            return true;
        }

        return false;
    }
}

class BeforeOperationOneHandler extends Handler
{
    public function Request($request)
    {
          if ($this->someOperations(new BeforeOperationOne())) {
              return;
          }

          $result = $this->operationOne(); // shape this too

          return $this->nextHandler->Request($result);
    }
}

class BeforeOperationTwoHandler extends Handler
{
    public function Request($request)
    {
          if ($this->someOperations(new BeforeOperationTwo())) {
              return;
          }

          $accessChecker = new AccessChecker($result); // shape this too
          $result = $this->operationTwo(accessChecker);

          return $this->nextHandler->Request($result);
    }
}

class BeforeOperationThreeHandler extends Handler
{
    public function Request($request)
    {
          if ($this->someOperations(new BeforeOperationThree())) {
              return;
          }

          $result = $this->operationThree(); // shape this too

          return $this->nextHandler->Request($result);
    }
}

class DefaultHandler extends Handler
{
    public function Request($request)
    {
          // this is the last step
    }
}




function execute($context)
{
    // some init actions
    $beforeOperationOneHandler = new BeforeOperationOneHandler();
    $beforeOperationTwoHandler = new BeforeOperationTwoHandler();
    $beforeOperationThreeHandler = new BeforeOperationThreeHandler();
    $defaultHandler = new DefaultHandler();

    // set the sequence of the elements
    // BeforeOperationOneHandler > BeforeOperationTwoHandler > BeforeOperationThreeHandler> DefaultHandler
    $beforeOperationOneHandler->setNextHandler($beforeOperationTwoHandler);
    $beforeOperationTwoHandler->setNextHandler($beforeOperationThreeHandler);
    $beforeOperationThreeHandler->setNextHandler($defaultHandler);

    return $beforeOperationOneHandler->Request($some_init);
}

这只是“责任链”模式的快速编写形式,所以我不假思索地复制了你的一些代码片段
我希望这将引导您找到更好的解决方案

【讨论】:

  • 感谢您的澄清。这让我重新思考解决方案。我这边走。
猜你喜欢
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-11
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
  • 2013-11-14
相关资源
最近更新 更多