2013-08-17 38 views
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,它后来用来执行“走出去” -REQUESTS。它还管理其私有的state变量中当前会话状态的存储。

现在,由于我的客户不需要担心会话状态在内部看起来像什么样,我想使用RequestHandler<?>,如图所示。但不幸的是,这给了我在state = handler.request...行错误:(?捕获#3的,字符串)

的方法请求的类型 RequestHandler不适用于参数 (对象,字符串)

有只改变了违规行的一个问题:

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

(这将会错误为“未投” -warning)

显然,这样我松散型检查我的state -object,但如果Client永远只能将它设置为null或由RequestHandler返回的东西,应该没有问题吧?

我知道我也可以只参数ClientClient<State>以及再利用State代替Object?无处不在。但我宁愿避免这一点,因为它(在我看来)只是在这种情况下的自重,将不得不随身携带,无论Client实例化或使用...

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

UPDATE:

有一个漂亮的解决了这个问题,如果一切都被一个方法里面发生的事情,而不是一类:

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实际上是。但是对于整个类没有等价的构造(一些推断的泛型论证)在那里?

+0

使该投会让你失去你的类型安全,因为你说。你为什么试图在这里使用泛型?这听起来像请求只接受'国家'并返回'国家'。有另外一种情况,RequestHandler将被用于其他事情吗? – nickrak

+0

@nickrak但是它不可能导致运行时异常,无论使用哪个参数'RequestHandler'实际指定,正确? (当然,只有当我的'Client'决定将它自己的非法内容保存在'state'中时) –

+0

如果你传递了非State的东西,会导致ClassCastException。这不会在编译时被捕获,因为客户端没有意识到类型限制。 – nickrak

回答

3

看起来好像可以制作Client通用的,反映了RequestHandler的类型。但是,如果要隐藏客户端内,你可以做这样的:

​​

注意,这使用客户端从关心泛型类型的RequestHandler的释放任何人。用户会对这样的代码:

RequestHandler<?> handler = ... ; 
Client client = new Client(handler); /* Look ma, no generics! */ 
client.go(); 
+0

美丽!这是我期待的答案。真棒!谢谢! +1√:) –

0

看来您的意图是客户应该能够定义消费并返回符合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; 
    ... 
} 

与您现有的代码的问题是,有包含在完全没有信息一个绝对的通配符。当通配符表示返回类型时,可能出现的情况是,您获得的类Object的对象没有有用的行为,并且作为参数类型,它基本上意味着客户端可能希望您提供一个对象任何特定的班级,但不是说哪个。

+0

作为一个例子,假设我的'RequestHandler'提供了某种键值存储,'request'方法用于存储值。然后,只要'RequestHandler'提供的put和get'request'完成他们的工作,'Client'就不会在意'State'中存储了什么。所以,我想保持“客户”的确切类型(正如我的问题最后提到的那样)。 –

+0

我试图理解你的问题,但它确实没有多大意义。如果您有使用泛型的理由,请使用它们;否则,请在'RequestHandler'上放置泛型类型。或者你是否只是在询问一个特定的用例,其中你的特定的“客户”类不关心?在这种情况下,使用'RequestHandler '。 – chrylis

+0

我只是在问这个特殊的用例,是的。所以使用'(RequestHandler )'''''''''''''''它不会失败,不管什么''实际上是吧? –

相关问题