问题描述
功能接口的描述如下:
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构造函数)。
解决方案
有几种方法可以解决此问题。以下是其中一些:
-
创建
MinionDeath
的实例,并将其作为参数传递。entry(EventType.DEATH,new MinionDeath());
-
Lambda表达式:这基本上是将
MinionDeath
的实现直接内联到lambda中。entry( EventType.DEATH,(event,state) -> ((MinionDeathEvent) event).getPlayer() .getBoard() .remove(deathEvent.getMinion()));
-
将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);