Java 基于可变状态与基于不可变事件的数据模型的计算成本
提前道歉,这是一个漫长的过程。我目前正在为这项运动创建一个记分板应用程序。基本规则是一名球员必须交替投一个红球和一个彩球,直到没有红球为止。之后,剩余的彩色球按值顺序封装。首先,我使用了一个传统的可变Java数据模型,如下所示:Java 基于可变状态与基于不可变事件的数据模型的计算成本,java,android,performance,list,immutability,Java,Android,Performance,List,Immutability,提前道歉,这是一个漫长的过程。我目前正在为这项运动创建一个记分板应用程序。基本规则是一名球员必须交替投一个红球和一个彩球,直到没有红球为止。之后,剩余的彩色球按值顺序封装。首先,我使用了一个传统的可变Java数据模型,如下所示: public class Player { public enum PlayerPosition { PLAYER_ONE, PLAYER_TWO }; String name; int score; int currentBreak;
public class Player {
public enum PlayerPosition { PLAYER_ONE, PLAYER_TWO };
String name;
int score;
int currentBreak;
}
public class Frame {
Player playerOne, playerTwo;
PlayerPosition breakingPlayer, playerAtTable;
int redsOnTable;
Ball[] remainingColours = new Ball[] { YELLOW, GREEN, BROWN, BLUE, PINK, BLACK };
}
因此,当球被封装时,该球的值被添加到球员的得分中,并且redsOnTable
被减少。这方面的问题是,虽然存储了中断的总数,但封装的球的顺序却不正确。但是,通过添加封装球的顺序,我现在将冗余数据引入到数据模型中,因为现在可以通过查看封装球的顺序来计算redsOnTable
因此,我开始怀疑是否可以将帧
视为一系列事件,例如
- 红球盆栽
- 黑球盆栽
- 红球盆栽
- 休息结束
- 红球盆栽
所有附加信息(例如,redsOnTable
,玩家的最高休息时间,表上剩余的总时间)都可以通过迭代此事件列表来计算,缺点是每次需要检索统计信息时都要迭代此列表,因此计算成本要大得多。我确实尝试过这样的事情,将每个玩家的突发事件拆分为列表
:
@AutoValue公共抽象类中断实现可包裹{
公共摘要列表getBallOrder();
公共静态中断创建(列出球){返回新的自动值_中断(球);}
}
@AutoValue公共抽象类框架实现了Parcelable{
公共摘要int getStartingReds();
公共摘要列表getBreakHistory();
公共抽象PlayerPosition getPlayerPositionAtTable();
公共抽象播放器位置getBreakingPlayer();
公共摘要生成器toBuilder();
}
但这导致了一个错误,我无法确定游戏是否在最后的颜色运行(黄色、绿色等),并且修复非常混乱,因此我想将所有事件存储在一个列表中。当前,每次刷新都会读取此列表5次(确定表中的玩家,获取玩家分数(x2),获取表中剩余的总分数,获取表中剩余的最低值球),但我可能可以重构它,以便在一次迭代中获取所有这些信息
所以我的问题归结为:
- 与传统的可变数据模型相比,基于不可变事件的数据模型所需的额外计算成本是否可能对近期低端Android手机的性能产生重大影响
- 是否有比
ArrayList
更有效的类用于存储和迭代这些事件(即,跳到下一个EndOfBreak
事件,获取列表中的红球事件数)。假设在一场漫长的安全战中,该列表可以轻松地显示100多个事件
- 对于频繁迭代的长列表,我还需要记住其他注意事项吗
编辑:关于该颜色运行错误。一旦所有的红色都被灌封,剩下的彩色球必须按价值顺序灌封,并且不要被重新放回桌子上。这里可能会发生许多情况:
1:
- 一号玩家将最后一个红点
- 一个玩家可以选择一种颜色(不是黄色)
- 玩家一不发黄,休息结束
- 球员二现在必须打黄线
2:
- 一号玩家将最后一个红点
- 球员一错过了下一次投篮(或犯规),中场休息结束
- 球员二现在必须打黄线
3:
- 一号玩家将最后一个红点
- 玩家一壶一黄,黄放回桌上
- 球员一号不发黄牌,休息结束
- 二号选手必须打黄牌
因此,如果我们纯粹按照potted顺序进行,而不使用EndOfBreak
事件,这会带来一个问题,因为pot的下一个球可能会也可能不会被放回桌上
- 在场景1中,我们知道黄色是下一个球,因为在最后一场比赛之后,红色不是黄色李>
- 在场景2中,最后一个被灌封的球是红色的,因此我们必须检查最后一个红色是否作为当前休息的一部分被灌封,以确定我们是否在彩色跑步中。如果我们只进行倒计时而不包括
EndOfBreak
事件,则不可能
- 在场景3中,封装的最后一个球不明确,因为它是黄色的。如果我们没有
EndOfBreak
信息,应用程序如何知道黄色是否还在桌面上李>
正如我之前提到的,我确实提出了一个修复方案,但它非常麻烦,并且仍然有一些边缘情况不起作用,这就是为什么我想将EndOfBreak
作为一个事件包含在这个列表中。如何使用HashMap
,其中关键是球的颜色,并且每次装入球时都会增加值?。要获得计数,您需要做的就是ballOrder.get(“reds”)
对于每个中断,这是一个新的HashMap
?即使如此,这也不能保持球的封装顺序,并且仍然会导致我提到的相同的颜色运行错误。我将编辑我的问题以包含该bug的详细信息
@AutoValue public abstract class Break implements Parcelable {
public abstract List<Ball> getBallOrder();
public static Break create(List<Ball> balls) { return new AutoValue_Break(balls); }
}
@AutoValue public abstract class Frame implements Parcelable {
public abstract int getStartingReds();
public abstract List<Break> getBreakHistory();
public abstract PlayerPosition getPlayerPositionAtTable();
public abstract PlayerPosition getBreakingPlayer();
public abstract Builder toBuilder();
}