接口上的循环依赖性

本文关键字:依赖性 循环 接口 | 更新日期: 2023-09-27 17:58:09

我正在重新分解和构建Win8应用程序解决方案。我一直在将我的关键组件分离到它们自己的项目中。我有:

  • Win8的主要项目使用MVVMLight(因此也使用SimpleIOC)
  • 一个包含我所有可序列化模型类的模型项目
  • 一个具有各种导航和序列化类的服务项目
  • 我所有接口的合同项目
  • 视图模型项目,包含主应用程序使用的视图模型

到目前为止,我已经做了一些工作,但有一次我无法找到最好的结构。在我的ViewModels项目中,我有一个数据映射器类。基本上,它接收一个模型并吐出一个视图模型。我一直试图将其转移到服务层,并为其创建了一个接口,但在接口中遇到了ViewModel类知识的依赖项,因此目前基本上是循环依赖项。

编辑:我应该解释一下ViewModels本身需要使用这个映射器。例如,我有一个完整的PageViewModel,它包含XAML页面所需的一切。其中之一是VehicleViewModels列表,这是一个包含一些视图特定属性的车辆列表。因此,PageViewModel将调用数据服务,获取车辆模型,然后使用映射器将其转换为VehicleViewModel。

这是界面。

namespace MyApp.Contracts
{
    public interface IDataMapperService
    {
        VehicleViewModel VehicleToVehicleViewModel(Vehicle v);
        TripViewModel TripToTripViewModel(Trip t);
    }
}

正如您所看到的,我想从这两个方法返回一个ViewModel对象。然而,ViewModel项目已经引用了这个Contracts项目,所以我目前不会构建它。

我曾想过为视图模型创建和Interface,但后来我要做很多工作来创建接口,我不确定这是最好的方法。我是不是忽略了一些显而易见的东西?

编辑:以下是当前接口的实际实现:

 public VehicleViewModel VehicleToVehicleViewModel(Vehicle v)
    {
        var newVehicle = new VehicleViewModel(v.VehicleID, v.Make, v.Model, v.Petrol, v.Registration);
        foreach (Trip t in v.Trips)
        {
            newVehicle.Trips.Add(TripToTripViewModel(t));
        }
        IQueryable<Trip> trips = v.Trips.AsQueryable();
        var now = DateTime.Now.Date;
        var firstofmonth = new DateTime(now.Year, now.Month, 1);
        while (now.DayOfWeek != DayOfWeek.Monday) now = now.AddDays(-1);
        var weektrips = from t in trips
                        where t.Date >= now
                        select t;
        var monthtrips = from t in trips
                         where t.Date >= firstofmonth
                         select t;
        newVehicle.TripsThisWeek = weektrips.Count();
        newVehicle.MilesThisWeek = (int)Math.Round(weektrips.Sum(t => t.Mileage), 0);
        newVehicle.TripsThisMonth = monthtrips.Count();
        newVehicle.MilesThisMonth = (int)Math.Round(monthtrips.Sum(t => t.Mileage), 0);
        return newVehicle;
    }
    public TripViewModel TripToTripViewModel(Trip t)
    {
        var newTrip = new TripViewModel(t.TripID, t.Date, t.Mileage);
        return newTrip;
    }

接口上的循环依赖性

您可以使用泛型来创建映射器接口。

namespace MyApp.Contracts
{
    public interface IDataMapperService<ViewModelT, ModelT>
    {
        ViewModelT ModelToViewModel(ModelT v);
    }
}

然后,您的服务可以返回一个IDataMapperService<VehicleViewModel, Vehicle>和一个IDataMapperService<TripViewModel, Trip>。您可以为视图模型和模型创建轻量级接口,以便与通用约束一起使用。

namespace MyApp.Contracts
{
    public interface IModel {}
    public interface IViewModel {}
    public interface IDataMapperService<ViewModelT, ModelT>
        where ViewModelT : IViewModel
        where ModelT : IModel
    {
        ViewModelT ModelToViewModel(ModelT v);
    }
}

然后,为了实现您的新接口,您需要创建一个映射器类。

public class DataMapperService : IDataMapperService<VehicleViewModel, Vehicle>
{
    public VehicleViewModel ModelToViewModel(Vehicle v)
    {
        //implementation goes here
    }
}

显然,您需要在引用您的合同、模型和视图模型项目的项目中实现此类。

如果我正确理解了这个问题,那么您正在尝试从一个对象映射到一个视图模型。如果是这种情况,编写自己的映射器工具可能对您的使用效率不高。检查Automapper它将允许您通过调用Mapper.map()方法将一个对象映射到另一个类型。

在我看来,你似乎过度思考了你真正想要实现的目标。如果您需要VehicleViewModel,则将车辆映射到VehicleView Model并调用映射方法。Automapper使这项工作变得非常容易。但通常情况下,您只需要一个位于任何可以访问视图模型的层上的中间映射器,它可以为不同的类型进行映射。