提问者:小点点

构造对象的一般方法


我有两个班:

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。我可以扩展DoorRequestWindowRequest的功能来提供实际的实现。现实生活中MakeOpenRequest的逻辑可以想象得要复杂得多,所以编写一个普通的工厂会导致大量的代码重复。这个方法唯一关心的是,它应该以命名的方式创建某些类型的实例,即为每个类单独定义。

我怀疑常规构造函数在这里会有所帮助,因为几乎没有任何泛型可以利用。构造方法必须是静态的,所以我不能真正指望它们的多态性。

处理这项任务最简单的方法是什么?反思是欺骗,但如果没有其他方法,那也没关系。


共2个答案

匿名用户

实例化泛型类型的唯一方法是所选类型具有无参数构造函数。这还要求您将其指定为泛型类型约束。

由于您希望代码对所有可能的类型都不可知,因此您的方法实际上无法决定要使用的正确消息(因为这需要知道特定类型,这会导致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。

在这种情况下,您应该寻找另一种方法,因为泛型不是解决问题的方法。最可能的情况是,您最好选择特定的方法(MakeDoorRequestMakeWindowRequest),因为如果消费者必须调用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