2013-08-17 37 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 )'''''''''''''''它不會失敗,不管什麼''實際上是吧? –

相關問題