0

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 > 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++){
                // 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 > 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++) {
                // 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 < 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?

5
  • 1
    Make one method that takes an additional parameter usePlot. (can be private) . Call that method from the other two. Commented May 30, 2020 at 9:25
  • If I understand you correct I trade duplicated code with one if / else Statement inside the for loop ? You can't have your cake and eat it too - I'll check how much it reduce the performance but it looks like this is the way to go Commented May 30, 2020 at 9:34
  • You can put the if outside, and have two loops. Commented May 30, 2020 at 9:35
  • This is a tradeoff I take. Commented May 30, 2020 at 9:40
  • Measure it first. Not sure if the JIT could do the same. Commented May 30, 2020 at 9:42

2 Answers 2

3

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

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

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().

Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.