我需要统一一些具有相同目的但使用相同方法但具有不同参数和结果的类。
这可能对你来说很奇怪,所以让我来解释一下。
我有多个连接到多个rest/web服务的类,以便从中获取数据。在本例中,假设所有这些rest都是天气预报服务。每个人都做同样的事情。一些地区的回报预测,但他们都在以自己的方式进行预测。对于每个服务,我都有实现从其中收集数据并映射到对象的类:
public class AForecast
{
public AForecastResult GetForecast (AForecastRequest request)
{
// Grab Forecast
}
}
public class BForecast
{
public BForecastResult GetForecast (BForecastRequest request)
{
// Grab Forecast
}
}
我调用这些类,获取预测数据,然后将其映射到我自己使用的对象中,这很好。我的问题是,现在我有13个预测服务。他们中的许多人都使用类似的方法将预测结果映射到我自己的对象中。下一个问题也是,现在可能只有我知道如何将新的预测添加到系统中。我希望将其统一起来,以便能够向Forecast服务实现中添加一些接口,以及一些基本预测映射器。
我创建了接口,但由于我不知道预测结果和请求看起来如何,所以它非常通用:
public interface IForecast<out TResult, in TRequest>
{
TResult GetForecast(TReqiest request)
}
对于每个预测,我创建了将实现IForecast
的单独接口
public interface IAForecast : IForecast<AForecastResult, AForecastRequest>
{
}
我的AForecast
实现开始是这样的:
public class AForecast : IAForecast
{
public AForecastResult GetForecast (AForecastRequest request)
{
// Grab Forecast
}
}
多亏了这一点,我有了Forecast服务,它有自己的接口,有通用的基本接口。
问题是当我想在基类中使用它时,基类将能够调用每个预测服务和地图对象:
public abstract ForecastBase
{
private readonly ?ForecastService _service;
protected ForecastBase(?ForecastService service)
{
_service = service;
}
public MapedObject GetForecast(DateTime date, string zip)
{
var request = GetRequest(date,zip);
var forecastServiceResponse = _service.GetForecast(request);
return Map(forecastServiceResponse);
}
protected abstract MapedObject Map(?Response response);
protected abstract ?Request GetRequest(DateTime date, string zip);
}
哦,这段时间太长了。现在最后一个问题是如何实现ForeCast
基类?根据我的架构,我怎么知道什么类型是?ForecastService
、?Request
和?Response
。我希望我能做这样的mapper:
public class AMap : ForecastBase
并且知道在这种情况下?ForecastService
将是IAForecast
,?Request
将是AForecastRequest
,?Response
将是AForecastResponse
?
如果你需要更多的解释,尽管问。
发布于 2019-06-04 02:27:47
我认为您需要的是关键字where
(不仅如此,它在这里还将扮演非常重要的角色)。
我像这样定义了请求和响应的接口:
public interface IForecastRequest
{
}
public interface IForecastResult
{
}
然后,我们可以继续定义Forecast本身的接口:
public interface IForecast<out TForecastResult, in TForecastRequest>
where TForecastResult : IForecastResult where TForecastRequest : IForecastRequest
{
TForecastResult GetForecast(TForecastRequest request);
}
这里发生的事情如下所示。除了您的解决方案之外,我们还限制泛型类型来实现请求和响应的接口。然后我们可以添加泛型方法来获取ForecastResult。顺便说一句,GetForecast
似乎也不是一个好名字。最好是GetResult
或GetForecastResult
,否则你会期望一个不同的返回类型。
现在我们可以实现BaseForecast了。我希望我正确地理解了这应该做什么。因为你称它为ForecastBase,所以我不确定它是否应该做与IForecast相同的事情。也许一个更好的名字在这里会是个好主意。我是这样实现的:
public abstract class BaseForecast<TForecastResult, TForecastRequest>
where TForecastResult : IForecastResult where TForecastRequest : IForecastRequest
{
private readonly IForecast<TForecastResult, TForecastRequest> _service;
protected BaseForecast(IForecast<TForecastResult, TForecastRequest> service)
{
_service = service;
}
public MappedObject GetForecast(DateTime date, string zip)
{
TForecastRequest request = GetRequest(date, zip);
TForecastResult forecastServiceResponse = _service.GetForecast(request);
return Map(forecastServiceResponse);
}
protected abstract MappedObject Map(TForecastResult response);
protected abstract TForecastRequest GetRequest(DateTime date, string zip);
}
这里,我们还必须添加where
,因为我们必须使用相同的约束来调用IForecast接口的泛型方法。您可以看到,在构造函数中,我们提供了IForecast实现的一个实例,这将是我们的服务。此服务使用我们在此基类的定义中也有的两个泛型类型。GetForecast方法现在可以使用IForecast的泛型方法和自己的泛型方法(GetRequest)来获取MappedObject (我不知道它是什么)。类型都是对齐的,您可以方便地对IForecastRequest和IForecastResult进行智能感知和编译时类型检查。
请让我知道我是否正确理解了ForecastBase的用途。
我希望这能帮到你。我很乐意尝试回答你在这方面的任何问题。
编辑:
我希望我能做那样的映射器..
您在其中显示的方式没有使用任何泛型参数。据我所知,如果不指定要使用的结果和请求,您将无法做到这一点。
我为此创建一个实现的方法如下:
// implement request
public class SomeForecastRequest : IForecastRequest
{
}
// implement result
public class SomeForecastResult : IForecastResult
{
}
// implement forecast itself
public class SomeForecast : IForecast<SomeForecastResult, SomeForecastRequest>
{
public SomeForecastResult GetForecast(SomeForecastRequest request)
{
// return the result you got from wherever
}
}
public class SomeMapper : BaseForecast<SomeForecastResult, SomeForecastRequest>
{
public SomeMapper(IForecast<SomeForecastResult, SomeForecastRequest> service) : base(service)
{
}
protected override SomeForecastRequest GetRequest(DateTime date, string zip)
{
// return a request from wherever
}
protected override MappedObject Map(SomeForecastResult response)
{
// map the response and return it
}
}
编辑2:我刚刚读了你的评论,内容如下:
..它们彼此没有关系。这些对象没有自己的接口,我也没有把它包装在自己的接口中
如果你想保持这种方式,你就不可能为你的映射器创建一个基类。映射器需要知道AForecast
有一个名为GetForecast
的方法。如果不是,它将如何调用它。如果你尝试这样做,你会陷入编译器错误的境地。你需要告诉编译器“这个类可以处理任何类,如果它有 GetForecast
**-method**”,否则它将拒绝尝试并调用GetForecast
。告诉编译器这一点的方法是说:“伙计,看,我得到了一个很棒的接口,它有GetForecast
-method。我只允许调用者使用一个实现这个接口的类,这样你就可以确保GetForecast
-method的存在。好吗?”这就是您使用where
关键字的原因,我感谢您的问题,因为这是一个关于如何使用它的非常好的(但不是太简单的)示例。
编辑3:
顺便说一句,没有什么可以阻止您使用类而不是IForecastRequest
和IForecastResult
的接口(当然,您可以更改名称,但其他一切都可以保持不变)。我不知道你的请求和响应对象应该做什么/存储什么,所以我不知道在这里通过接口使用类是不是正确的调用。
我只是想说这也是可能的。
我很乐意听到您的一些反馈:)
https://stackoverflow.com/questions/56432293
复制相似问题