英文:
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;
}
这种情况无法通过这种方式解决,因为只有一个返回值。当然,我可以创建一个带有 widthf
和 xi
属性的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 > 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?
答案1
得分: 3
你可以使用消费者(consumers)来处理for
循环内的不同处理。定义一个新的函数式接口,将xx
和yy
值作为参数:
@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 > 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()
.
答案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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论