我有两个班:
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
的逻辑可以想象得要复杂得多,所以编写一个普通的工厂会导致大量的代码重复。这个方法唯一关心的是,它应该以命名的方式创建某些类型的实例,即为每个类单独定义。
我怀疑常规构造函数在这里会有所帮助,因为几乎没有任何泛型可以利用。构造方法必须是静态的,所以我不能真正指望它们的多态性。
处理这项任务最简单的方法是什么?反思是欺骗,但如果没有其他方法,那也没关系。
实例化泛型类型的唯一方法是所选类型具有无参数构造函数。这还要求您将其指定为泛型类型约束。
由于您希望代码对所有可能的类型都不可知,因此您的方法实际上无法决定要使用的正确消息(因为这需要知道特定类型,这会导致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
,那么唯一可能的解决方案是根据特定类型更改其行为,这对于泛型来说不是一个好的用例。这表明设计不好,违反了OCP。
在这种情况下,您应该寻找另一种方法,因为泛型不是解决问题的方法。最可能的情况是,您最好选择特定的方法(MakeDoorRequest
,MakeWindowRequest
),因为如果消费者必须调用MakeOpenRequest,这对他们来说并不重要
你在问题中提到事情可能会变得更加复杂。此时,您应该考虑工厂模式,而不是试图对泛型做同样的事情。
你想错了方向。您需要一个创建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
。