假设您有以下接口
public interface Action {
public State execute(State state);
}
public interface State {
public Collection<Action> getPossibleActions();
}
这个方法
public static Collection<State> getAllSuccessorStates(State state){
Collection<State> allSuccessors = new HashSet<>();
for (Action action: state.getPossibleActions()){
State successorState = action.execute(state);
allSuccessors.add(successorState);
allSuccessors.addAll(getAllSuccessorStates(successorState));
}
return allSuccessors;
}
一个具体的国家可以是一个棋盘,一个动作就是棋子在棋盘上的运动。显然,Chess-Actions需要知道具体的State类:
public class ChessAction implements Action {
@Override
public ChessState execute(ChessState state) {...}
}
当然,这不是覆盖执行的允许方式。实现这个的正确方法是什么,所以你可以拥有对具体状态进行操作的具体动作,你可以将它们作为getAllSuccessorStates的参数给出?
我想到了Generics并且也得到了指向Generics的答案,但这带来了新的问题。如果我像这样编写Action类:
public interface Action<E extends State> {
public E execute(E state);
}
我将在ChessState类中遇到以下问题:
@Override
public Collection<Action<State>> getPossibleActions() {
Collection<Action<State>> actions = new ArrayList<>();
actions.add(new ChessAction());
return actions;
}
行Actions.add导致以下错误:类型Collection&gt;中的方法add(Action)不适用于参数(ChessAction)
现在我可以宣布行动为
Collection<Action<ChessState>> actions = new ArrayList<>();
但不是允许的返回类型。
答案 0 :(得分:3)
您可以使用泛型(需要java 1.5或更高版本):
public interface Action<T extends State> {
public T execute(T state);
}
public class ChessAction implements Action<ChessState> {
@Override
public ChessState execute(ChessState state) {...}
}
希望有所帮助。
答案 1 :(得分:1)
我现在找到了一个令人满意的解决方案,它正常工作,不需要instanceof并且不会产生编译警告:
public interface Action<E extends State<?>> {
public E execute(E state);
}
public interface State<E extends Action<?>> {
public Collection<E> getPossibleActions();
}
public static <A extends Action<S>, S extends State<A>> Collection<S> getAllSuccessorStates(S state){
Collection<S> allSuccessors = new HashSet<>();
for (A localAction: state.getPossibleActions()){
S successorState = localAction.execute(state);
allSuccessors.add(successorState);
allSuccessors.addAll(getAllSuccessorStates(successorState));
}
return allSuccessors;
}
使用getAllSuccessorStates的示例(我放弃了具体类的实现细节,但Point应该是显而易见的。您可以将getAllSuccessorStates方法与任何具体的State类一起使用,在返回集合中获取此类的实例并使用它们)
public class TestState implements State<TestAction> {...}
public class TestAction implements Action<TestState> {...}
public static void main(String[] args) {
TestState initialState = new TestState("1");
Collection<TestState> allSuccessorStates = getAllSuccessorStates(initialState);
for (TestState state: allSuccessorStates){
System.out.println(state.getStateStr());
}
}
这个问题起源于这本书&#34; AI-A现代的方法&#34;作者:Stuart Russel和Peter Norvig,如果读这本书的人有同样的问题并寻找解决方案。在书中,Action和State方法都在一个问题类中,但我认为这样OO设计更好。
答案 2 :(得分:0)
好吧,ChessState
必须与execute
接口中的Action
签名相同。如果您要求ChessAction.execute
仅接受ChessState
,则可以写:
public class ChessAction implements Action {
@Override
public State execute(State state)
{
if (!(state instanceof ChessState))
throw new SomeException ();
ChessState cs = (ChessState) state;
...
}
}
答案 3 :(得分:0)
你需要实现相同的继承方法,它将起作用,因为State是CheesState的超类。
public class ChessAction implements Action {
@Override
public State execute(State state) {...}
}
在execute方法中,你可以使用polymorph方法(在State中定义并重新定义ChessState),或者你可以转换为ChessState(ChessState s =(ChessState)状态;),然后根据需要使用它