"Early return" 最佳实践和 DRY
"Early return" best practice and DRY
我想知道在某些情况下是否有更好的 "braking out" 方法。让我用代码更好地解释一下:
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
}
我们在这里重复了条件,当用户从事件中访问时,在上下文中设置用户。我能想到的选项是:
- 丑陋的 do-while(false) 或 goto(我最好保留它现在的样子)
- 将其提取到方法中并将条件更改为
if (!$this->handleEvent($event, $context)) { return; }
- 这没有多大帮助,想不出更好的名称句柄不会说它正在返回某些东西
- 为操作构建闭包数组并循环检查。我们可以假设所有事件 class 都是从具有 accessGranted 方法的公共 class 派生的。这可能很丑陋,因为某些操作需要来自以前 "steps" 的数据,我必须将它们放在外面并传递它们。
- 抛出并捕获用户有权访问的异常 - 另一个糟糕的解决方案。
你有什么更好的想法吗?
@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);
}
只是写得很快 "chain of responsibility" 模式所以我不小心复制了你的一些代码片段
我希望这会引导您找到更好的解决方案
我想知道在某些情况下是否有更好的 "braking out" 方法。让我用代码更好地解释一下:
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
}
我们在这里重复了条件,当用户从事件中访问时,在上下文中设置用户。我能想到的选项是:
- 丑陋的 do-while(false) 或 goto(我最好保留它现在的样子)
- 将其提取到方法中并将条件更改为
if (!$this->handleEvent($event, $context)) { return; }
- 这没有多大帮助,想不出更好的名称句柄不会说它正在返回某些东西 - 为操作构建闭包数组并循环检查。我们可以假设所有事件 class 都是从具有 accessGranted 方法的公共 class 派生的。这可能很丑陋,因为某些操作需要来自以前 "steps" 的数据,我必须将它们放在外面并传递它们。
- 抛出并捕获用户有权访问的异常 - 另一个糟糕的解决方案。
你有什么更好的想法吗?
@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);
}
只是写得很快 "chain of responsibility" 模式所以我不小心复制了你的一些代码片段
我希望这会引导您找到更好的解决方案