【问题标题】:Inserting extra code into Java for loops在 Java for 循环中插入额外代码
【发布时间】:2014-03-14 14:08:32
【问题描述】:

我有一批精灵(带纹理的 OpenGL ES 2.0 Quads),我循环移动它们。这是我的代码的简化版本:

//'sprite' & other values have been are assumed to exist for the purpose of the question

public void moveQuadBatch(){

    //Loop for as many sprites as there are to draw
    for (loop = 0; loop < sprite.number; loop++){

        moveQuadNumber(loop); //this method will move the sprite that corresponds to the number loops so we can move through the entire batch and move each individual sprite


    }
}

现在,对于某些批次,有一个倒数计时器或其他一些条件(而对于其他批次则没有,如上)。因此,我为这些对象创建了一个类似的方法,如下所示:

public void moveQuadBatchWithCheck(){

    //Loop for as many sprites as there are to draw
    for (loop = 0; loop < sprite.number; loop++){

        //Only do this if the particular sprite's countdown/delay counter has reached 0 (counting down from another method not seen here)
        if (sprite.delay[loop]<0){

            moveQuadNumber(loop); //this method will move the sprite that corresponds to the number loops so we can move through the entire batch and move each individual sprite

        }
    }
}

但是,我对此并不完全满意,因为有很多代码重复。除了使用这两种方法之外,有什么方法可以使用第一种方法并以某种方式将附加检查“滑流”到 for 循环中?或者以其他方式减少我在这里的重复?这是一个简单的例子,还有其他的,目前我有多种方法都非常相似。

编辑

如前所述,以上内容有所简化。我可以有一些 for 循环来检查另一个值(例如延迟除外),有些可以检查 2 个条件。

【问题讨论】:

  • 为方法添加一些参数。根据参数的值,您可以采取不同的操作。
  • 您能举个例子解释一下@B.J.Smegma 吗?谢谢
  • 查看 Claudiu 的回答。

标签: java for-loop foreach conditional-statements code-duplication


【解决方案1】:
public void moveQuadBatch(bool checkDelay) {
    for (loop = 0; loop < sprite.number; loop++){
        if (!checkDelay || sprite.delay[loop] < 0) {
             moveQuadNumber(loop);
        }
    }
}

现在moveQuadBatch(false) 是您的第一个函数,moveQuadBatch(true) 是您的第二个函数。


至于“插入额外代码”,您基本上是在谈论函数。在 Python 中,一种优雅的方法是将函数传入并将所有逻辑卸载到函数中,例如:

    def moveQuadBatch(predicate=None):
        for loop, sprite in enumerate(self.sprites): 
            if not predicate or predicate(loop, sprite):
                self.moveQuadNumber(loop)

然后你会这样使用它:

inst.moveQuadBatch()  
inst.moveQuadBatch(lambda loop, sprite: sprite.delay[loop] < 0)
inst.moveQuadBatch(lambda loop, sprite: sprite.doesItBlend(loop))

您可以在 Java 中做同样的事情,但不那么简洁:您必须定义一个谓词类和它的实例。这是 B.J. Smegma 提倡的方法。

public interface QuadBatchPredicate {
    public boolean shouldMove(int loop, Sprite sprite);
}

你的函数应该是这样的:

public void moveQuadBatch(QuadBatchPredicate pred) {
    for (loop = 0; loop < sprite.number; loop++){
        if (pred == null || pred(loop, sprite)) {
             moveQuadNumber(loop);
        }
    }
}
public void moveQuadBatch() {
    moveQuadBatch(null);
}

然后你可以使用匿名类来定义谓词:

moveQuadBatch();
moveQuadBatch(new QuadBatchPredicate() {
    public boolean shouldMove(int loop, Sprite sprite) {
        return sprite.delay[loop] < 0;
    }
});
moveQuadBatch(new QuadBatchPredicate() {
    public boolean shouldMove(int loop, Sprite sprite) {
        return sprite.doesItBlend();
    }
});

比 Python 解决方案略显笨拙,但它抓住了重点。现在,您可以通过将谓词内联地定义为您想要的任何内容,将代码“插入”到函数中。另外,您可以保存常用的,这样您就不会到处重复它们:

QuadBatchPredicate checkBlends = new QuadBatchPredicate() {
    public boolean shouldMove(int loop, Sprite sprite) {
        return sprite.doesItBlend();
    }
};

【讨论】:

  • 感谢@Claudiu,减少 cmets?我总是读到那些不评论他们的代码的人的抱怨?关于“循环”变量,第一条评论解释说所有变量/对象都假定存在 - 这是为了避免不相关的代码。没关系,但是,如上所述,这仅适用于 2 种不同的可能性,在我的实际代码中,我还有很多其他的,有些对“延迟”等以外的东西进行了额外的检查......有什么方法可以使用main for 循环,但更改其中的代码以进行我需要检查的任何内容 - 谢谢! :-)
  • @Zippy:你能举一些你做的检查的例子吗?这将有助于整理出一个答案。啊,谢谢我错过了第一条评论,我认为它不相关..
  • @Zippy:哦,关于更少的 cmets,我的意思是你不应该让 cmets 只说出代码的作用,例如int i; //i will be our loop iteratorfor (i=0; i &lt; 100; i++) { //loop i starting from 0 and ending at 99, incrementing by 1 each time 等。我知道sprite[delay] &lt; 0 的意思是“只有在特定精灵的倒计时/延迟计数器达到 0 时才这样做”,不需要拼写出来 =)。实际上,如果您这样拼写,​​则更难阅读。
  • 我明白,请随时编辑 cmets :-) 我总是喜欢尽可能多地发表评论,因为我觉得这会使问题更具可读性。
  • @Zippy:看看我的编辑是否更符合您的喜好。真的允许你使用任何你想要的谓词。函数式编程 FTW
【解决方案2】:

我会为延迟检查创建一个单独的方法,并像这样更改您的方法:

public void moveQuadBatchWithCheck(bool check){
    for (loop = 0; loop < sprite.number; loop++){
        if(check){
            if (sprite.delay[loop]<0){
                moveQuadNumber(loop); 
                }
       }
       else{
           moveQuadNumber(loop);
           }
    }

那么当你想检查调用方法时,使用 true 在参数中。

虽然不确定这是否是您正在寻找的,但我希望它会有所帮助。

【讨论】:

  • 同意,请参阅主要问题中的编辑。谢谢:-)
  • 你说得对。我正在打电话,所以我花了一段时间来回答这个问题。现在我看到了你的回答,我觉得自己很愚蠢。
【解决方案3】:

制作这样的界面:

public interface MyInteface {
void do_something(int loop);
}

根据您的需要对该接口进行不同的实现,例如

public class MyInterfaceImpl {
    public void do_something(int loop) {
         if (!checkDelay || sprite.delay[loop] < 0) {
              moveQuadNumber(loop);
         }
    }

那么你的方法可能看起来很简单:

public void moveQuadBatch(MyInterface interface) {
    for (int loop = 0; loop < sprite.number; loop++){
        interface.do_something(loop)
    }
}

【讨论】:

  • 对@B.J.Smegma 非常感兴趣。所以基本上,我会在 MyInterfaceImpl 类中为我需要的每个可能的结果创建一个方法,然后把它放在我的循环中?
  • 你将为你在 for 循环中所做的每一件不同的事情创建接口的实现。然后,您可以根据需要使用这些不同的实现来调用您的方法。
  • 基本上是map的精简实现,而我的是filter的精简实现..我不喜欢Java
  • 你是说我需要为每个可能的结果定义一个不同的接口/类吗?或者,例如在同一接口中有一个“doSomething(int loop)”,然后是一个 doSomethingElse(int loop)' 方法。如果是后者,我将如何调用所需的任何方法?我不能显式输入 interface.doSomethingElse(loop) ,因为这又意味着,有多个 moveQuadBatch() 方法会破坏目的。或者也许我不完全理解这一点?谢谢!
【解决方案4】:

您可以为您的精灵添加“效果”。

public class Sprite {
    private boolean active = true;
    private ArrayList<Effect> effects = new ArrayList<>();

    public void update(int time) {
        for(Effect e: effects) {
            e.update(this, time);
        }
    }

    public void addEffect(Effect effect) {
        effects.add(effect);
    }

    public void setActive(boolean active) {
        this.active = active;
    }
}

public interface Effect {
    void update(Sprite sprite, int time);
}

public class Delay implements Effect {
    private int delay;

    public Delay(int delay) {
        this.delay = delay;
    }

    public void update(Sprite sprite, int time) {
        delay -= time;
        if(delay > 0) sprite.setActive(false);
        else sprite.setActive(true);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-14
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-30
    • 1970-01-01
    相关资源
    最近更新 更多