Рефакторинг для соответствия принципу СУХОЙ

Я пытаюсь найти способ рефакторинга этого кода, чтобы не повторять один и тот же код во многих местах. Я ищу СУХОЙ принцип.

Это пример 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;
}

Это еще один пример createRule() в другом классе, как вы можете видеть, код почти такой же. Как преобразовать это в принцип СУХОГО — вы бы создали новый метод или класс для выполнения той же логики?

   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;
}

0

Решение

Я думаю, что я бы создал один общий метод, как это:

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,
]);
}
}

и в вашем контроллере вы бы использовали его так:

(новый Деймон ($ server, $ command, $ user)) -> process ();

На всякий случай — имейте в виду, у вас есть $deamon переменная, которая не определена (она не определена также в вашем контроллере)

1

Другие решения

Расширяет

Вы можете заставить их расширять один и тот же базовый класс:

class foo{
public function myMethod(){}
}

class bar extends foo{ }

class biz extends foo{ }

Теперь оба подкласса имеют метод myMethod

Черта характера

Вы можете использовать черту для общей функциональности

trait foo{
public function myMethod(){}
}

class bar{
use foo;
}

class biz{
use foo;
}

Что касается фактической функциональности, я бы разбил ее на 3 метода:
Я собирался написать что-то об этом, но я вижу, @Marcin Nabiałek, имеет хороший ответ на эту часть. Я просто хотел рассказать о том, как структурировать классы для повторного использования общего метода.

Приветствия.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector