将功能接口的实现作为参数传递

问题描述

功能接口的描述如下:

package models;

@FunctionalInterface
public interface EventReducer {
    void apply(Event event,GameState state);
}

我在以下类中实现该接口:

package models.reducers;

import models.Event;
import models.EventReducer;
import models.GameState;
import models.events.MinionDeathEvent;

public class MinionDeath implements EventReducer {

    @Override
    public void apply(Event event,GameState state) {
        MinionDeathEvent deathEvent = (MinionDeathEvent)event;
        deathEvent.getPlayer().getBoard().remove(deathEvent.getMinion());
    }
}

如何将实现作为参数传递?例如,

    private static final Map<EventType,EventReducer> ReducersMap = Map.ofEntries(
        entry(EventType.DEATH,MinionDeath::apply);
    );

显然,MinionDeath::apply并非可行之路

解决方法

问题

在当前解决方案中,我们尝试在没有类实例的情况下引用实例方法

entry(EventType.DEATH,MinionDeath::apply);

运行时无法单独创建MinionDeath的实例,主要是因为不能保证存在无参数的构造函数(在这种特殊情况下它存在,但并非每个类都具有no- args构造函数)。

解决方案

有几种方法可以解决此问题。以下是其中一些:

  1. 创建MinionDeath的实例,并将其作为参数传递。

    entry(EventType.DEATH,new MinionDeath());
    
  2. Lambda表达式:这基本上是将MinionDeath的实现直接内联到lambda中。

    entry(
        EventType.DEATH,(event,state) -> ((MinionDeathEvent) event).getPlayer()
                .getBoard()
                .remove(deathEvent.getMinion()));
    
  3. 将lambda定义为例如静态方法,并将其作为方法引用传递。

    public class Game { // The class name is an assumption of mine
    
        ...
    
        private static void processMonsterDeathEvent(Event event,GameState state) {
            MinionDeathEvent deathEvent = (MinionDeathEvent)event;
            deathEvent.getPlayer().getBoard().remove(deathEvent.getMinion());
        }
    
        private static final Map<EventType,EventReducer> ReducersMap = Map.ofEntries(
            entry(EventType.DEATH,Game::processMonsterDeathEvent)
        );
    
        ...
    }
    

    此解决方案的备注:这与原始解决方案不同,因为我们现在引用的是静态方法。我们还可以将apply中的方法MinionDeath更改为static。在这种情况下,我们应该从类定义中删除... implements EventRecorder,因为不再需要它。

,

您要传递MinionDeath的实例,只要它是具有唯一一种抽象方法的功能接口本身,即合格。 MinionDeath也是EventReducer,并且可以分配给该类。

private static final Map<EventType,EventReducer> ReducersMap = Map.ofEntries(
    entry(EventType.DEATH,new MinionDeath())
);

请注意,这实际上与您传递lambda表达式本身相同:

private static final Map<EventType,EventReducer> ReducersMap = Map.ofEntries(
    entry(
        EventType.DEATH,// key
        (event,state) -> {                                                   // value
            MinionDeathEvent deathEvent = (MinionDeathEvent)event;
            deathEvent.getPlayer().getBoard().remove(deathEvent.getMinion());
        }
    )
);

还请注意,如果您编写entry(EventType.DEATH,MinionDeath::apply),那不是您想要的,并且将创建与该lambda表达式兼容的新功能接口:

interface TriConsumer<T,R,S> {
    void consume(T t,R r,S s);
}
Map<EventType,TriConsumer<MinionDeath,Event,GameState>> map = new HashMap<>();
map.put(EventType.DEATH,MinionDeath::apply);

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...