我有兩個班級:
class DoorRequest : IRequest
{
string message;
}
class WindowRequest : IRequest
{
string message;
}
它們不相互繼承,而是實作了一個公共介面。我想有一個通用的方法來創建這些類的實體。在語意上等同于:
public static T MakeOpenRequest<T>() where T : IRequest
{
// If T is DoorRequest return new DoorRequest{message="please open the door"}
// If T is WindowRequest return new WindowRequest{message="please open the window"}
}
對我來說重要的是函式的結果是T,不是IRequest。我可以擴展功能DoorRequest并WindowRequest提供實際實作。MakeOpenRequest可以想象現實生活中的邏輯要復雜得多,所以寫一個普通的工廠會導致大量的代碼重復。該方法唯一關心的是它應該以命名方式創建某些型別的實體,即為每個類分別定義。
我懷疑常規建構式在這里會有所幫助,因為幾乎沒有任何通用性可以利用。構造方法必須是靜態的,所以我不能真正指望它們的多型性。
處理這項任務的最簡潔方法是什么?反思是作弊,但如果沒有其他辦法,那也沒關系。
uj5u.com熱心網友回復:
TL;DR
你真的應該考慮一個不依賴泛型的解決方案;因為您預期的代碼對于該泛型型別的所有具體事物的行為方式都不相同。這是泛型不是正確方法的第一個危險信號。
實體化泛型型別的唯一方法是所選型別是否具有無引數建構式。這還需要您將其指定為泛型型別約束。
由于您希望您的代碼在所有可能型別的情況下作業,因此您的方法實際上無法決定要使用的正確訊息(因為這需要知道特定型別,這會導致 OCP 違規)。因此,應該在具體IRequest實作本身中定義訊息。
但是,這使您的方法本身除了呼叫建構式之外別無他法:
interface IRequest { }
class DoorRequest : IRequest
{
public string Message { get; }
public DoorRequest()
{
Message = "Please open the door";
}
}
class WindowRequest : IRequest
{
public string Message { get; }
public WindowRequest()
{
Message = "Please open the window";
}
}
static class Foo
{
public static T MakeOpenRequest<T>() where T : IRequest, new()
{
var obj = new T();
return obj;
}
}
如果您需要在MakeOpenRequest函式中而不是在IRequest實作本身中決定訊息,并且訊息特定于T所使用的型別,那么唯一可能的解決方案是MakeOpenRequest根據特定型別更改其行為,這不是泛型的良好用例。這表明設計不佳,并且違反了 OCP。
在這種情況下,您應該尋找替代方法,因為泛型不是要走的路。最有可能的是,您最好選擇特定的方法 ( MakeDoorRequest, MakeWindowRequest),因為消費者是否必須呼叫MakeOpenRequest<WindowRequest>or并不重要MakeWindowRequest,因為兩者都需要對具體型別有相同的了解。
您在問題中提到事情可能會變得更加復雜。在這一點上,您應該考慮工廠模式,而不是嘗試對泛型做同樣的事情。
uj5u.com熱心網友回復:
你想錯了。你想要一個創建IRequest物件的工廠,依賴于傳遞的一些引數。
例子:
enum RequestTypes {
DoorRequest,
WindowRequest
}
class RequestFactory {
public IRequest Create(RequestType requestType) {
switch(requestType) {
case RequestType.DoorRequest:
return new DoorRequest();
case RequestType.WindowRequest:
return new WindowRequest();
default:
throw new ArgumentException("requestType");
}
}
}
不需要泛型,只需要很好的老式多型性。
這假設IRequest是正確的。它應該是:
interface IRequest {
string message;
}
您永遠不需要將其強制轉換為顯式DoorRequest,您只需使用回傳的IRequest.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/384271.html
上一篇:泛型類方法的TypescriptReturnType問題
下一篇:存根異步泛型方法
