将功能接口的实现作为参数传递
Pass implementation of functional interface as parameter
功能接口描述如下:
package models;
@FunctionalInterface
public interface EventReducer {
void apply(Event event, GameState state);
}
我实现接口如下class:
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
不是一条路要走
问题
在当前的解决方案中,我们尝试在没有 class
实例的情况下引用实例方法
entry(EventType.DEATH, MinionDeath::apply);
运行时无法自行创建 MinionDeath
的实例,主要是因为不能保证 no-args 构造函数存在(在这种特殊情况下它存在,但不是每个 class 有一个 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)
);
...
}
对该解决方案的评论:这与原始解决方案不同,因为我们现在引用的是静态方法。我们还可以将 MinionDeath
中的方法 apply
更改为 static
。在这种情况下,我们应该从 class 定义中删除 ... implements EventRecorder
,因为它不再需要了。
你想传递一个 MinionDeath
的实例,只要它 是 一个功能接口本身,只有一个抽象方法,因此是合格的。另外 MinionDeath
是 EventReducer
并且可以分配给 class.
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);
功能接口描述如下:
package models;
@FunctionalInterface
public interface EventReducer {
void apply(Event event, GameState state);
}
我实现接口如下class:
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
不是一条路要走
问题
在当前的解决方案中,我们尝试在没有 class
实例的情况下引用实例方法entry(EventType.DEATH, MinionDeath::apply);
运行时无法自行创建 MinionDeath
的实例,主要是因为不能保证 no-args 构造函数存在(在这种特殊情况下它存在,但不是每个 class 有一个 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) ); ... }
对该解决方案的评论:这与原始解决方案不同,因为我们现在引用的是静态方法。我们还可以将
MinionDeath
中的方法apply
更改为static
。在这种情况下,我们应该从 class 定义中删除... implements EventRecorder
,因为它不再需要了。
你想传递一个 MinionDeath
的实例,只要它 是 一个功能接口本身,只有一个抽象方法,因此是合格的。另外 MinionDeath
是 EventReducer
并且可以分配给 class.
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);