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