Cal*_*man 6 java reflection visitor
我正在开发一个小型游戏模板,其中包含如下节点的世界:
World
|--Zone
|----Cell
|------Actor
|------Actor
|--------Item
Run Code Online (Sandbox Code Playgroud)
如果a World可以包含多个Zone对象,则a Zone可以包含多个Cell对象,依此类推.
所有这些实现的Node接口,它有一些方法,如getParent,getChildren,update,reset等.
我希望能够Task在单个节点上执行给定,或者从节点(由指定的Task)指定的树上递归执行.
为了解决这个问题,我希望这是一个"可插拔"系统,这意味着我希望玩家/开发人员能够动态地向树中添加新类型.我还考虑过基类型的转换:
public void doTask(Actor node)
{
if(!(node instanceof Goblin)) { return; }
Goblin goblin = (Goblin) node;
}
Run Code Online (Sandbox Code Playgroud)
最初我被吸引使用访客模式来利用双重调度,允许每个例程(访问者)根据Node被访问的类型行事.但是,这会引起一些复杂情况,特别是当我想Node在树中添加新类型时.
作为替代方案,我编写了一个实用类,它使用反射来查找适用于该方法的最具体方法Node.
我现在关心的是表现 ; 因为会有相当多的反思查找和调用,我担心我的游戏性能(每秒可能有数百或数千个这样的调用)会受到影响.
这似乎解决了这两种模式的问题,但却使每个新的代码Task更加丑陋.
我看到它的方式,我有三个允许这种动态调度的选项(除非我遗漏了明显/模糊的东西,这就是为什么我在这里):
Node类型(不修改原始代码就不可能)Node放弃添加新类型我错过了一些明显的东西吗?我熟悉许多四人组模式,以及游戏编程模式中的模式.任何帮助将在这里受到赞赏.
要清楚,我不是在问这些是哪个是"最好的".我正在寻找这些方法的替代方案.
因此,在对 Java 8 Lambda 以及如何反射性地构造它们进行一些研究之后,我提出了BiConsumer从Method反射性获得的对象创建 a 的想法,第一个参数是应该调用该方法的实例,第二个参数是argument 是方法的实际参数:
private static <T, U> BiConsumer<T, U> createConsumer(Method method) throws Throwable {
BiConsumer<T, U> consumer = null;
final MethodHandles.Lookup caller = MethodHandles.lookup();
final MethodType biConsumerType = MethodType.methodType(BiConsumer.class);
final MethodHandle handle = caller.unreflect(method);
final MethodType type = handle.type();
CallSite callSite = LambdaMetafactory.metafactory(
caller,
"accept",
biConsumerType,
type.changeParameterType(0, Object.class).changeParameterType(1, Object.class),
handle,
type
);
MethodHandle factory = callSite.getTarget();
try {
//noinspection unchecked // This is manually checked with exception handling.
consumer = (BiConsumer<T,U>) factory.invoke();
}catch (ClassCastException e) {
LOGGER.log(Level.WARNING, "Unable to cast to BiConsumer<T,U>", e);
}
return consumer;
}
Run Code Online (Sandbox Code Playgroud)
BiConsumer创建后,它会HashMap使用参数类型和方法名称作为键缓存在 a 中。然后可以像这样调用它:
consumer.accept(nodeTask, node);
Run Code Online (Sandbox Code Playgroud)
这种调用方法几乎完全消除了反射引起的调用开销,但它确实有一些问题/限制:
BiConsumer,因此只能将一个参数传递到该方法中(该accept方法的第一个参数必须是应调用该方法的实例)。
HashMap查找)。我可以通过使用自定义功能接口(类似于类Invoker而不是 Java 的接口BiConsumer)来澄清这段代码,但到目前为止,它完全符合我想要的性能。
| 归档时间: |
|
| 查看次数: |
1035 次 |
| 最近记录: |