重构以符合 DRY 原则
Refactoring to comply with the DRY principle
我正在尝试找到一种重构这段代码的方法,这样我就不会在很多地方重复相同的代码。我正在寻找DRY原则。
这是createDaemon()
方法的一个例子。
function createDaemon($server, $command, $user)
{
try {
DB::beginTransaction();
$model = $server->daemons()->create([
'command' => $command,
'user' => $user,
]);
$shell = $this->getCommand('add-daemon', [
'daemonId' => $daemon->id,
'command' => $command,
'user' => $user,
]);
$this->pushToQueue($model, $shell);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
}
return $model;
}
这是另一个 class 中 createRule()
的另一个示例,您可以看到代码几乎相同。如何将其重构为 DRY 原则 - 您会创建一个新方法还是 class 来执行相同的逻辑?
public function createRule($server, $name, $port, $ipAddress = null)
{
try {
DB::beginTransaction();
$model = $server->rule()->create([
'name' => $name,
'port' => $port,
]);
$shell = $this->getCommand('rule', [
'port' => $port,
'ipAddress' => $ipAddress
]);
$this->pushToQueue($model, $shell);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
}
return $model;
}
我想我会创建一个像这样的通用方法:
public function createGeneralRule(Closure $closure)
{
try {
DB::beginTransaction();
[$model, $shell] = $closure();
$this->pushToQueue($model, $shell);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
}
return $model;
}
现在您可以像这样使用它了:
function createDaemon($server, $command, $user)
{
return $this->createGeneralRule(function() use ($server, $command, $user) {
$model = $server->daemons()->create([
'command' => $command,
'user' => $user,
]);
$shell = $this->getCommand('add-daemon', [
'daemonId' => $daemon->id,
'command' => $command,
'user' => $user,
]);
return [$model, $shell];
}
}
和
public function createRule($server, $name, $port, $ipAddress = null)
{
return $this->createGeneralRule(function() use ($server, $name, $port, $ipAddress) {
$model = $server->rule()->create([
'name' => $name,
'port' => $port,
]);
$shell = $this->getCommand('rule', [
'port' => $port,
'ipAddress' => $ipAddress
]);
return [$model, $shell];
}
}
当然您也可以使用 类,但这实际上取决于您要重用此代码的次数以及您真正需要的灵活性。
使用类可能是这样的:
abstract class Rule
{
public function process()
{
try {
DB::beginTransaction();
$model = $this->model();
$shell = $this->shell();
$this->pushToQueue($model, $shell);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
}
return $model;
}
protected function getCommand($name, $data)
{
// here you put implementation you had before of getCommand
}
abstract protected function model();
abstract protected function shell();
}
class Deamon extends Rule
{
protected $server;
protected $command;
protected $user;
public function __construct($server, $command, $user)
{
$this->server = $server;
$this->command = $command;
$this->user = $user;
}
protected function model()
{
return $this->server->daemons()->create([
'command' => $this->command,
'user' => $this->user,
]);
}
protected function shell()
{
return $this->getCommand('add-daemon', [
'daemonId' => $daemon->id, // this is unknown, should be passed in constructor?
'command' => $this->command,
'user' => $this->user,
]);
}
}
在您的控制器中,您可以这样使用它:
(new Deamon($server, $command, $user))->process();
以防万一 - 请记住您有 $deamon
未定义的变量(它也未在您的控制器中定义)
延长
你可以让它们扩展相同的基础class:
class foo{
public function myMethod(){}
}
class bar extends foo{ }
class biz extends foo{ }
现在两个子class都有方法myMethod
特质
您可以使用特征来实现共享功能
trait foo{
public function myMethod(){}
}
class bar{
use foo;
}
class biz{
use foo;
}
至于实际功能,我会将其分解为 3 种方法:
我本来打算在上面写点东西,但我看到@Marcin Nabiałek,对那部分有一个很好的答案。我只是想介绍如何构建 classes 以便重新使用通用方法。
干杯。
我正在尝试找到一种重构这段代码的方法,这样我就不会在很多地方重复相同的代码。我正在寻找DRY原则。
这是createDaemon()
方法的一个例子。
function createDaemon($server, $command, $user)
{
try {
DB::beginTransaction();
$model = $server->daemons()->create([
'command' => $command,
'user' => $user,
]);
$shell = $this->getCommand('add-daemon', [
'daemonId' => $daemon->id,
'command' => $command,
'user' => $user,
]);
$this->pushToQueue($model, $shell);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
}
return $model;
}
这是另一个 class 中 createRule()
的另一个示例,您可以看到代码几乎相同。如何将其重构为 DRY 原则 - 您会创建一个新方法还是 class 来执行相同的逻辑?
public function createRule($server, $name, $port, $ipAddress = null)
{
try {
DB::beginTransaction();
$model = $server->rule()->create([
'name' => $name,
'port' => $port,
]);
$shell = $this->getCommand('rule', [
'port' => $port,
'ipAddress' => $ipAddress
]);
$this->pushToQueue($model, $shell);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
}
return $model;
}
我想我会创建一个像这样的通用方法:
public function createGeneralRule(Closure $closure)
{
try {
DB::beginTransaction();
[$model, $shell] = $closure();
$this->pushToQueue($model, $shell);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
}
return $model;
}
现在您可以像这样使用它了:
function createDaemon($server, $command, $user)
{
return $this->createGeneralRule(function() use ($server, $command, $user) {
$model = $server->daemons()->create([
'command' => $command,
'user' => $user,
]);
$shell = $this->getCommand('add-daemon', [
'daemonId' => $daemon->id,
'command' => $command,
'user' => $user,
]);
return [$model, $shell];
}
}
和
public function createRule($server, $name, $port, $ipAddress = null)
{
return $this->createGeneralRule(function() use ($server, $name, $port, $ipAddress) {
$model = $server->rule()->create([
'name' => $name,
'port' => $port,
]);
$shell = $this->getCommand('rule', [
'port' => $port,
'ipAddress' => $ipAddress
]);
return [$model, $shell];
}
}
当然您也可以使用 类,但这实际上取决于您要重用此代码的次数以及您真正需要的灵活性。
使用类可能是这样的:
abstract class Rule
{
public function process()
{
try {
DB::beginTransaction();
$model = $this->model();
$shell = $this->shell();
$this->pushToQueue($model, $shell);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
}
return $model;
}
protected function getCommand($name, $data)
{
// here you put implementation you had before of getCommand
}
abstract protected function model();
abstract protected function shell();
}
class Deamon extends Rule
{
protected $server;
protected $command;
protected $user;
public function __construct($server, $command, $user)
{
$this->server = $server;
$this->command = $command;
$this->user = $user;
}
protected function model()
{
return $this->server->daemons()->create([
'command' => $this->command,
'user' => $this->user,
]);
}
protected function shell()
{
return $this->getCommand('add-daemon', [
'daemonId' => $daemon->id, // this is unknown, should be passed in constructor?
'command' => $this->command,
'user' => $this->user,
]);
}
}
在您的控制器中,您可以这样使用它:
(new Deamon($server, $command, $user))->process();
以防万一 - 请记住您有 $deamon
未定义的变量(它也未在您的控制器中定义)
延长
你可以让它们扩展相同的基础class:
class foo{
public function myMethod(){}
}
class bar extends foo{ }
class biz extends foo{ }
现在两个子class都有方法myMethod
特质
您可以使用特征来实现共享功能
trait foo{
public function myMethod(){}
}
class bar{
use foo;
}
class biz{
use foo;
}
至于实际功能,我会将其分解为 3 种方法: 我本来打算在上面写点东西,但我看到@Marcin Nabiałek,对那部分有一个很好的答案。我只是想介绍如何构建 classes 以便重新使用通用方法。
干杯。