避免重复的代码,如果唯一的区别是在一个 for 循环中的方法调用。

huangapple go评论65阅读模式
英文:

Avoid duplicated code if the only diffence is a method call in a for loop

问题

我有这两个在Java中编写的方法:

public void fillRect(float x, float y, float width, float height, Color color) {
    int xi = mapX(x);
    int yi = mapY(y);

    int heightf =  mapHeight(height);
    int widthf  = mapWidth(width);

    if (xi + widthf > pixelWidth){
        widthf -= xi + widthf - pixelWidth;
    }
    if (yi + heightf > pixelHeight){
        heightf -= yi + heightf - pixelHeight;
    }

    if (xi < 0) {
        widthf += xi;
        xi = 0;
    }
    if (yi < 0) {
        heightf += yi;
        yi = 0;
    }

    for (int xx = xi; xx < xi + widthf; xx++){
        for (int yy = yi; yy < yi + heightf; yy++){
            // 这里是与另一种方法的区别
            setPixel(xx,yy,color);
        }
    }
}
public void fillRect(float x, float y, float width, float height,float transparency, Color color) {
    int xi = mapX(x);
    int yi = mapY(y);

    int heightf =  mapHeight(height);
    int widthf  = mapWidth(width);

    if (xi + widthf > pixelWidth){
        widthf -= xi + widthf - pixelWidth;
    }
    if (yi + heightf > pixelHeight){
        heightf -= yi + heightf - pixelHeight;
    }

    if (xi < 0) {
        widthf += xi;
        xi = 0;
    }
    if (yi < 0) {
        heightf += yi;
        yi = 0;
    }

    for (int xx = xi; xx < xi + widthf; xx++){
        for (int yy = yi; yy < yi + heightf; yy++) {
            // 这里是与另一种方法的区别
            // 这个方法比setPixel()慢
            plot(xx,yy,transparency,color);
        }
    }
}

我习惯于编写一个类似 validateBoundary(float* x,float* y, float* width, float *height): void 的方法,其中包括了一些 if 语句,然后调用它,但显然在Java中这是行不通的。
那么对于这样的问题有什么解决方案呢?我们可以编写一个名为 validateBoundaryWidthf(xi, widhtf, pixelWitdth) 的方法,该方法返回 widthf 的新值。但是像下面这样的情况:

if (xi < 0) {
    widthf += xi;
    xi = 0;
}

这种情况无法通过这种方式解决,因为只有一个返回值。当然,我可以创建一个带有 widthfxi 属性的POJO,并返回它,但我认为这在CPU / 内存方面可能会有一些开销。那么解决这个重复代码问题的正确方法是什么呢?

英文:

I have this two methods written in java:

public void fillRect(float x, float y, float width, float height, Color color) {
        int xi = mapX(x);
        int yi = mapY(y);

        int heightf =  mapHeight(height);
        int widthf  = mapWidth(width);


        if (xi + widthf &gt; pixelWidth){
            widthf -= xi + widthf - pixelWidth;
        }
        if (yi + heightf &gt; pixelHeight){
            heightf -= yi + heightf - pixelHeight;
        }


        if (xi &lt; 0) {
            widthf += xi;
            xi = 0;

        }
        if (yi &lt; 0) {
            heightf += yi;
            yi = 0;
        }

        for (int xx = xi; xx &lt; xi + widthf; xx++){
            for (int yy = yi; yy &lt; yi + heightf; yy++){
                // here is the difference between the other method
                setPixel(xx,yy,color);

            }
        }
    }
public void fillRect(float x, float y, float width, float height,float transparency, Color color) {
        int xi = mapX(x);
        int yi = mapY(y);

        int heightf =  mapHeight(height);
        int widthf  = mapWidth(width);

        if (xi + widthf &gt; pixelWidth){
            widthf -= xi + widthf - pixelWidth;
        }
        if (yi + heightf &gt; pixelHeight){
            heightf -= yi + heightf - pixelHeight;
        }


        if (xi &lt; 0) {
            widthf += xi;
            xi = 0;

        }
        if (yi &lt; 0) {
            heightf += yi;
            yi = 0;
        }

        for (int xx = xi; xx &lt; xi + widthf; xx++){
            for (int yy = yi; yy &lt; yi + heightf; yy++) {
                // here is the difference between the other method
                // this Method is slower then setPixel() 
                plot(xx,yy,transparency,color);
            }
        }
    }

I'm used to write a method like this validateBoundary(float* x,float* y, float* width, float *height): void which includes the 'if-statments' and call it instead but clearly this won't be happen in Java.
What is the solution for problems like this? We could write a Methode validateBoundaryWidthf(xi, widhtf, pixelWitdth) which returns the the new value for widthf. But something like this:

if (xi &lt; 0) {
     widthf += xi;
     xi = 0;
}

can't be a solved by this because there is only one return value. Sure I could create a POJO with the attributes widthf and xi an return this instead but I assume this is comes expensive in terms of cpu / memory. So what is the proper way solving this duplicated code issue?

答案1

得分: 3

你可以使用消费者(consumers)来处理for循环内的不同处理。定义一个新的函数式接口,将xxyy值作为参数:

@FunctionalInterface
public interface PointConsumer {
    void accept(int x, int y);
}

然后你可以添加一个新的方法performOnPoints,它接受所有需要的参数,以及一个PointConsumer参数。它可能看起来像这样:

public void performOnPoints(float x, float y, float width,
                            float height, PointConsumer consumer) {
    int xi = mapX(x);
    int yi = mapY(y);

    int heightf =  mapHeight(height);
    int widthf  = mapWidth(width);

    if (xi + widthf > pixelWidth){
        widthf -= xi + widthf - pixelWidth;
    }
    if (yi + heightf > pixelHeight){
        heightf -= yi + heightf - pixelHeight;
    }

    if (xi < 0) {
        widthf += xi;
        xi = 0;
    }
    if (yi < 0) {
        heightf += yi;
        yi = 0;
    }

    for (int xx = xi; xx < xi + widthf; xx++){
        for (int yy = yi; yy < yi + heightf; yy++){
            consumer.accept(xx, yy);
        }
    }
}

然后你可以像这样重写现有的fillRect方法:

public void fillRect(float x, float y, float width, float height, Color color) {
    performOnPoints(x, y, width, height, (xx, yy) -> setPixel(xx, yy, color));
}

public void fillRect(float x, float y, float width, float height,
        float transparency, Color color) {
    performOnPoints(x, y, width, height, (xx, yy) -> plot(xx, yy, transparency, color));
}

正如你所看到的,它们都使用相同的循环代码以及所有特殊的if()语句,但你只需要编写这段代码一次。对于不同的参数,你将使用不同的消费者对象,一个将调用setPixel(),另一个将调用plot()

英文:

You can use consumers to handle the different handling inside the for loop. Define a new functional interface which takes the xx and yy values as arguments:

@FunctionalInterface
public interface PointConsumer {
	void accept(int x, int y);
}

Then you add a new method performOnPoints with all the arguments needed and with one PointConsumer argument. It might look like this:

public void performOnPoints(float x, float y, float width,
                            float height, PointConsumer consumer) {
    int xi = mapX(x);
    int yi = mapY(y);

    int heightf =  mapHeight(height);
    int widthf  = mapWidth(width);


    if (xi + widthf &gt; pixelWidth){
        widthf -= xi + widthf - pixelWidth;
    }
    if (yi + heightf &gt; pixelHeight){
        heightf -= yi + heightf - pixelHeight;
    }


    if (xi &lt; 0) {
        widthf += xi;
        xi = 0;

    }
    if (yi &lt; 0) {
        heightf += yi;
        yi = 0;
    }

    for (int xx = xi; xx &lt; xi + widthf; xx++){
        for (int yy = yi; yy &lt; yi + heightf; yy++){
            consumer.accept(xx, yy);
        }
    }
}

Then you can rewrite your existing fillRect methods like this:

public void fillRect(float x, float y, float width, float height, Color color) {
    performOnPoints(x, y, width, height, (xx, yy) -&gt; setPixel(xx, yy, color));
}

public void fillRect(float x, float y, float width, float height,
        float transparency, Color color) {
    performOnPoints(x, y, width, height, (xx, yy) -&gt; plot(xx,yy,transparency,color);
}

As you see they both use the same looping code with all the special if() statements, but you have this code only once. For the different arguments you will use a different consumer object, one will call setPixel(), the other will call plot().

答案2

得分: 0

你可以定义 public void fillRect(bool plot, float x, float y, float width, float height, float transparency, Color color) 函数,其中 plot 表示应使用哪种实现。当值为 false 时,使用第一个选项。当值为 true 时,使用第二个选项。

英文:

You can define public void fillRect(bool plot, float x, float y, float width, float height,float transparency, Color color) where plot indicates which implementation should be used. When false use the first option. When true use the second option.

huangapple
  • 本文由 发表于 2020年5月30日 17:22:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/62100404.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定