简体   繁体   English

重构比较器/运算符块以提高DRY的性能并降低CRAP级别

[英]Refactoring comparision/operators blocks to DRY up and reduce C.R.A.P level

I set out to make a small project around a bounch of classes that return generators (php 5.5). 我开始围绕返回生成器的类(php 5.5)创建一个小项目。

The main motivation for the small project was to expand on my TDD journey, fiddle with generators and have a package I could throw on packagist for later use. 这个小项目的主要动机是在我的TDD旅程中扩展,弄弄发电机,并准备一个可以放在包装上供以后使用的包装。

The current state of the whole "project" can be found at Github 整个“项目”的当前状态可以在Github上找到

All tests are green, the methods does what I want. 所有测试都是绿色的,这些方法可以满足我的要求。 Now I want to refactor as I there is lots of dublication. 现在我要重构,因为我有很多重复的内容。

    /**
    *   Returns a Generator with a even range.
    *
    *   getEven(10); // 10,12,14,16,18,20,22 ...
    *   getEven(null, 10); // 10,8,6,4,2,0,-2,-4 ...
    *   getEven(10, null, 2); // 10,6,2, -2 ...
    *   getEven(10,20); // 10,12,14,16,18,20
    *   getEven(20,10); // 20,18,16,14,12,10
    *   getEven(10,20,2); // 10,14,18
    *
    *   @param int|null $start
    *   @param int|null $end
    *   @param int $step
    *   @throws InvalidArgumentException|LogicException
    *   @return Generator
    */
    public function getEven( $start = null, $end = null, $step = 1 )
    {
        // Throws LogicException
        $this->throwExceptionIfAllNulls( [$start, $end] );
        $this->throwExceptionIfInvalidStep($step);

        // Throws InvalidArgumentException
        $this->throwExceptionIfNotNullOrInt( [$start, $end] );

        // infinite increase range
        if(is_int($start) && is_null($end))
        {
            // throw LogicException
            $this->throwExceptionIfOdd($start);

            $Generator = function() use ($start, $step)
            {
                for($i = $start; true; $i += $step * 2)
                {
                    yield $i;
                }
            };
        }
        // infinite decrease range
        elseif(is_int($end) && is_null($start))
        {
            // throws LogicException
            $this->throwExceptionIfUneven($end);

            $Generator =  function() use ($end, $step)
            {
                for($i = $end; true; $i -= $step * 2)
                {
                    yield $i;
                }
            };
        }
        // predetermined range
        else 
        {
            // throws LogicException
            $this->throwExceptionIfUneven($start);
            $this->throwExceptionIfUneven($end);

            // decrease
            if($start >= $end)
            {
                $Generator = function() use ($start, $end, $step)
                {
                    for($i = $start; $i >= $end; $i -= $step * 2)
                    {
                        yield $i;
                    }
                };
            }
            // increase
            else
            {
                $Generator = function() use ($start, $end, $step)
                {
                    for($i = $start; $i <= $end; $i += $step * 2)
                    {
                        yield $i;
                    }
                };
            }
        }

        return $Generator();
    }

The class also has a method named getOdd (and yes it looks alot like it ;) ) 该类还具有一个名为getOdd的方法(是的,它看起来很多;))

The main dublication is the closures $Generator = function() ... and the difference is mostly operators such as + - * / and arguments in the for loop. 主要的复制项是闭包$Generator = function() ... ,区别主要是运算符,例如+ - * /和for循环中的参数。 This is mainly the same in the rest of th class. 这在其余的班级中基本上是相同的。

I read Dynamic Comparison Operators in PHP and come to the conclusion that there is no native method like compare(...) 我阅读了PHP中的动态比较运算符 ,得出的结论是没有像compare(...)这样的本机方法compare(...)

Should I make a private/protected method for comparison. 我应该使用私有/受保护的方法进行比较吗? If so should I make a new class/function for this? 如果是这样,我应该为此新建一个类/函数吗? I do not think it belongs in the current class. 我认为它不属于当前班级。

Is it something else I am missing, I am unsure on how to DRY this up, in a proper way? 我还缺少其他东西吗?我不确定如何以适当的方式将其干燥吗?

Btw. 顺便说一句。 iknow a getEven, getOdd is kinda silly when i got a getRange With step function, but it is a more general refactoring / pattern question. 知道一个getEven,当我得到带有step函数的getRange时,getOdd有点傻,但这是一个更通用的重构/模式问题。

Update @github the getEven and getOdd are now removed... 更新 @github的getEven和getOdd现在已被删除...

The code below has not been tested or verified to work, but I have faith in it and at least it shows one possible way of removing the multiple generator functions. 以下代码尚未经过测试或验证,但是我相信它,至少它显示了删除多个生成器功能的一种可能方法。

As you state yourself, the duplication you are trying to remove is mainly in the generator function. 在声明自己时,要删除的重复项主要是在generator函数中。 If you look into this you can see that every generator function you have can be written as this: 如果您仔细研究一下,可以看到您拥有的每个生成器函数都可以这样编写:

function createGenerator($index, $limit, $step) {
    return function() use($index, $limit, $step) {
        $incrementing = $step > 0;
        for ($i = $index; true; $i += 2 * $step) {
            if (($incrementing && $i <= $limit) || (!$incrementing && $i >= $limit)) {
                yield $i;
            }else {
                break;
            }
        }
    };
}

In order to utilize this you need to do some magic with the input arguments and it helps (at least makes it pretty) to define some constants. 为了利用这一点,您需要对输入参数做一些魔术,它有助于(至少使它漂亮)定义一些常量。 PHP allready got a PHP_INT_MAX constant holding the greatest value possible for an integer, however it does not got a PHP_INT_MIN . PHP已经准备好了一个PHP_INT_MAX常量,该常量持有一个整数可能的最大值,但是它没有一个PHP_INT_MIN So I would define that as a constant of its own. 因此,我将其定义为一个常量。

define('PHP_INT_MIN', ~PHP_INT_MAX);

Now lets take a look at the four cases in your function. 现在,让我们看一下函数中的四种情况。

1) Infinite increase range 1)无限增加范围

Infinte is a rather bold claim here, if we change it to "greatest value possible given the constraints of an int" we get a finite range from $index to PHP_INT_MAX , hence by setting $limit = PHP_INT_MAX; Infinte在这里是一个相当大胆的主张,如果将其更改为“在给定int约束的情况下可能的最大值”,我们将获得从$indexPHP_INT_MAX的有限范围,因此可以通过设置$limit = PHP_INT_MAX; the above mentioned generator function will still be the same. 上述生成器功能将保持不变。

//$limit = PHP_INT_MAX;
createGenerator($index, PHP_INT_MAX, $step);

2) Infinite decrease range 2)无限减少范围

The same argument as above can again be used here, but with a negativ $step and swapping $index and $limit ; 这里可以再次使用与上述相同的参数,但是要加上负的$step并交换$index$limit

//$index = $limit;
//$limit = PHP_INT_MIN;
//$step *= -1;
createGenerator($limit, PHP_INT_MIN, -1 * $step);

3) Predetermined decreasing range 3)预定的下降范围

Swap and negate once again. 交换并再次取反。

//$temp = $index;
//$index = $limit;
//$limit = $temp;
//$step *= -1;
createGenerator($limit, $index, -1 * $step);

4) Predetermined increasing range 4)预定范围

Well this is just the default case, where all arguments are given. 好吧,这只是默认情况,其中给出了所有参数。 And nothing needs to change. 不需要改变。

createGenerator($index, $limit, $step);

The revised code 修改后的代码

public function getEven($index = null, $limit = null, $step = 1) {
    // Throws LogicException
    $this->throwExceptionIfAllNulls([$index, $limit]);
    $this->throwExceptionIfInvalidStep($step);

    // Throws InvalidArgumentException
    $this->throwExceptionIfNotNullOrInt([$index, $limit]);

    //Generator function
    function createGenerator($index, $limit, $step) {
        return function() use($index, $limit, $step) {
            $incrementing = $step > 0;
            for ($i = $index; true; $i += 2 * $step) {
                if (($incrementing && $i <= $limit) || (!$incrementing && $i >= $limit)) {
                    yield $i;
                }else {
                    break;
                }
            }
        };
    }
    // infinite increase range
    if (is_int($index) && is_null($limit)) {
        // throw LogicException
        $this->throwExceptionIfodd($index);
        return createGenerator($index, PHP_INT_MAX, $step);
    }
    // infinite decrease range
    elseif (is_int($limit) && is_null($index)) {
        // throws LogicException
        $this->throwExceptionIfodd($limit);
        return createGenerator($limit, PHP_INT_MIN, -1*$step);
    }
    // predetermined range
    else {
        // throws LogicException
        $this->throwExceptionIfodd($index);
        $this->throwExceptionIfodd($limit);

        // decrease
        if ($index >= $limit) {
            return createGenerator($limit, $index, -1 * $step);
        }
        return createGenerator($index, $limit, $step);
    }
}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM