简体   繁体   English

重构以符合DRY原则

[英]Refactoring to comply with the DRY principle

I am trying to find a way to refactor this code so I don't to repeat same code in many places. 我试图找到一种重构此代码的方法,以免在很多地方重复相同的代码。 I am looking for DRY principle. 我正在寻找DRY原则。

This is an example of createDaemon() method. 这是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;
    }

This is another example of createRule() in another class, as you can see the code is almost the same. 这是另一个类中的createRule()另一个示例,因为您可以看到代码几乎相同。 How to refactor this into DRY principle - would you create a new method or class to do the same logic? 如何将其重构为DRY原理-您会创建一个新方法或类来执行相同的逻辑吗?

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

I think I would create one common method like this: 我想我会创建一个像这样的常用方法:

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

and now you can do use it like this: 现在您可以像这样使用它:

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

and

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

Of course you could also use classes, but it really depends how many times you are going to reuse this code and what flexibility do you really need. 当然,您也可以使用类,但这实际上取决于要重用此代码的次数以及您真正需要的灵活性。

Using classes it could be something like this: 使用类可能是这样的:

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

and in your controller you would use it like this: 在您的控制器中,您将像这样使用它:

(new Deamon($server, $command, $user))->process(); (新的Deamon($ server,$ command,$ user))-> process();

Just in case - keep in mind you have $deamon variable which is not defined (it's not defined also in your controller) 以防万一-请记住,您有未定义的$deamon变量(在控制器中也未定义)

Extends 延伸

You can make them extend the same base class: 您可以使它们扩展相同的基类:

class foo{
     public function myMethod(){}
}

class bar extends foo{ }

class biz extends foo{ }

Now both subclasses have the method myMethod 现在两个子类都具有方法myMethod

Trait 特征

You can use a trait for the shared functionality 您可以将特征用于共享功能

trait foo{
   public function myMethod(){}
}

class bar{
  use foo;
}

class biz{ 
  use foo;
}

As for the actual functionality I would break it down into 3 methods: I was going to write something on it but I see @Marcin Nabiałek, has a good answer for that part. 至于实际的功能,我将其分解为3种方法:我打算在上面写一些东西,但是我看到@MarcinNabiałek在这方面有很好的答案。 I just wanted to cover how to structure the classes in order to re-use a common method. 我只想介绍如何构造类以重新使用通用方法。

Cheers. 干杯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 代码是否符合Liskov的替代原则? - Does code comply with Liskov's substitution principle? 使此类符合依赖性倒置原则 - Making this class comply with the Dependency Inversion principle 多前缀路由和DRY原理 - Multiple prefixed routes and DRY principle PHP / Codeigniter模型函数的干原理 - PHP/Codeigniter Dry Principle on Model functions DRY原则检查用户权限,如何避免每页重复代码? - DRY principle in check user rights, how to avoid repeat of code on every page? 如何在保持DRY原理的同时确保一个对象仅属于一个集合? - How can I ensure that an object only belongs to one collection, while maintaining the DRY principle? 使用 DRY 原则帮助在服务 class 中创建灵活的基本“查找”方法 - Help creating a flexible base 'find' method in a service class using the DRY principle 重构比较器/运算符块以提高DRY的性能并降低CRAP级别 - Refactoring comparision/operators blocks to DRY up and reduce C.R.A.P level 如果过多的if-then-else使得代码不可读,那么如何遵循“不重复自己(DRY)”原则? - how to adhere to the Don't-Repeat-Yourself (DRY) principle when there will be too many if-then-else making the code unreadable? 方法重构? - Method refactoring?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM