2

假设我有一个接口,它描述了可能的请求处理程序,这些处理程序可以在客户端存储的某些客户端会话状态的上下文中为客户端请求的操作提供服务:

public interface RequestHandler<State> {
    // Perform action in the context of currentState and return updated state
    public State request(State currentState, String action);
}

为了便于实现 RequestHandlers,我添加了泛型类型State,它封装了所有需要的客户端会话数据。

现在,一个简单的客户端可能如下所示:

public class Client {
    private final RequestHandler<?> handler;
    private Object state;

    Client(RequestHandler<?> handler) {
        // Initialize the RequestHandler to use for "go"-requests
        this.handler = handler;
        // Initialize our client state to "null"
        this.state   = null;
    }

    public void go() {
        // Execute "go"-request in current state and update state
        state = handler.request(state, "go");  // <= this is an error (see below)
    }
}

在创建过程中,它会被提供一个RequestHandler,然后它会使用它来执行“go”-requests。它还在私有state变量中管理其当前会话状态的存储。

现在,由于我的客户不需要担心会话状态在内部实际上是什么样子,我想使用RequestHandler<?>如图所示。但是,不幸的是,这给了我一个错误state = handler.request...

RequestHandler 类型中的方法 request(capture#3-of ?, String) 不适用于参数 (Object, String)

将违规行更改为:

state = ((RequestHandler<Object>) handler).request(state, "go");

(这会将错误变成“未经检查的演员表”警告)

显然,这样我就可以对我的state-object 进行类型检查,但是如果Client唯一将它设置为null或由 . 返回的东西RequestHandler,应该没有问题,对吧?

我知道我也可以参数化Client,然后Client<State>State任何地方使用。但我宁愿避免这种情况,因为(在我看来)在这种情况下它只是自重,必须在任何实例化或使用 a 的地方随身携带......Object?Client

没有办法投射state(?),对吧?

更新:

如果一切都发生在单个方法而不是类中,那么这个问题有一个很好的解决方案:

public <State> void go(RequestHandler<State> handler) {
    State state = null;
    state = handler.request(state, "go");
    state = handler.request(state, "go again");
    state = handler.request(state, "go one more time");
}

这样,我可以在任何地方调用,而不必总是指定State实际是什么。但是整个类没有等效的构造(一些推断的通用参数)吗?

4

2 回答 2

3

似乎可以制作Client通用的,反映RequestHandler. 但是,如果你想在客户端隐藏它,你可以这样做:

public final class Client
{

  private final CaptureHelper<?> helper;

  <T> Client(RequestHandler<T> handler) {
    this.helper = new CaptureHelper<T>(handler);
  }

  public void go()
  {
    helper.request("go");
  }

  private final class CaptureHelper<T>
  {

    private final RequestHandler<T> handler;

    private T state;

    private CaptureHelper(RequestHandler<T> handler) {
      this.handler = handler;
    }

    private void request(String action)
    {
      state = handler.request(state, action);
    }

  }

}

请注意,这使任何使用客户端的人都不必关心其RequestHandler. 用户会有这样的代码:

RequestHandler<?> handler = ... ;
Client client = new Client(handler); /* Look ma, no generics! */
client.go();
于 2013-08-17T05:58:13.317 回答
0

看来您的意图是客户端应该能够定义s 来使用和返回符合接口RequestHandler的各种对象。State如果是这样,您需要像这样定义您的接口,以便客户端可以指定State他们正在使用的特定类型:

public interface RequestHandler<StateType> {
    // Perform action in the context of currentState and return updated state
    public StateType request(StateType currentState, String action);
}

如果您的Client类打算是通用的(在非技术意义上),那么它也应该是通用的(在技术意义上),允许子类或其自己的客户指定State对象的类型:

public class Client<StateType> {
    private StateType state;
    ...
}

您现有代码的问题是绝对通配符中绝对不包含任何信息。当通配符表示返回类型时,您可能会得到一个 class 的对象Object,没有任何有用的行为,并且作为参数类型,这基本上意味着客户端可以期望您提供任何对象特定的课程,但没有说哪个。

于 2013-08-17T04:42:39.203 回答