使用依赖注入解决循环依赖问题

6
我有三个类实现了它们的接口。
订单
public interface IOrderService
{
   //SomeOrderFunction()
}

public class OrderService: IOrderService
{
    //SomeOrderFunction();
}

驱动程序

public interface IDriverService
{
   //SomeDriverFunction()
}

public class DriverService: IDriverService
{
    //SomeDriverFunction();
}

计划--使用驱动程序和计划服务。
public interface IPlanService
{
   //SomePlanFunction()
}

public class PlanService: IPlanService
{
    private readonly IOrderService _orderService;
    private readonly IDriverService _driverService;

    public PlanService(IDriverService driverService, IOrderService orderService)
    {
      _orderService = orderService;
      _driverService = driverService;
    }

    //PlanFunctionsThatUseServices();
}

我现在遇到的问题是,当订单或司机发生更改时,订单服务和司机服务需要与计划服务进行通信,我该如何做才能避免循环依赖?
编辑: 具体来说,我一直在考虑创建第四个服务来管理所有其他服务,例如这篇文章中所解释的服务。 Breaking Dependency Cycles 关于这种实现方式让我困惑的是我的计划类,我的计划类是否同时实现新类和IPlan接口?

3
我认为没有这个参考是不可能的。或者,你可以创建第四个类来管理三个服务之间的通信。 - rbm
3个回答

6

通过事件。

创建事件处理程序接口:

public interface IEventSubscriber<TEvent>
{
    void Handle(TEvent evt);
}

然后定义一个事件:
public class PlanCreated
{
    public int PlanId { get; set; }
    //and other properties.
}

现在让其他类来实现它:
public class DriverService : IDriverService, IEventSubscriber<PlanCreated>
{
    public void Handle(PlanCreated evt)
    {
        //handle it here.
    }
}

现在,要发布事件需要另一个界面:

public interface IEventPublisher
{
    void Publish<TEvent>(TEvent evt);
}

这可以从你的类中调用:

public class PlanService: IPlanService
{
    private readonly IOrderService _orderService;
    private readonly IDriverService _driverService;

    public PlanService(IDriverService driverService, IOrderService orderService, IEventPublisher publisher)
    {
      _orderService = orderService;
      _driverService = driverService;
    }

    public void PlanFunctionsThatUseServices()
    {

       //business code....


      _publisher.Publish(new PlanCreated(){ Id = plan.Id } );
}

.. 要调用它,我们可以使用服务定位(实现细节):

public class EventPublisher : IEventPublisher
{

    public EventPublisher(YourFavoriteContainer container)
    {
    }


    public void Publish<TEvent>(TEvent evt)
    {
        using (var scope = _container.BeginLifetimeScope())
        {
            var handlers = scope.ResolveAll<IEventSubscriber<TEvent>>();
            foreach (var handler in handlers)
            {
                //TODO: Handle exceptions=
                handler.Handle(evt);
            }
        }

    }
}

作为结果,您可以获得类之间的低耦合度。

1
可以公正地提到,这种方法是一种被称为事件聚合器的众所周知的模式。这使得OP有机会自行查找更多信息。 - Wiktor Zychla
2
我不这么认为。事件聚合器是将来自多个对象的事件通道汇集到一个单一对象中,以简化客户端的注册。该模式更多地涉及处理同一对象类型的多个实例的事件。 - jgauffin

3

IPlanService 替换为 Func<IPlanService> 并注入到 IOrderServiceIDriverService 中。这样可以“打破”容器需要创建的实例链。

public class OrderService {
    public OrderService(Func<IPlanService> planServiceFactory) {
        _planServiceFactory = planServiceFactory;
    }

    private readonly Func<IPlanService> _planServiceFactory;

    public void SomeOrderFunction() {
        _planServiceFactory().Notify(...);
    }
}

1

首先,重新思考你的方法。

其次,如果你仍然坚持有循环依赖,你可以通过让依赖的服务负责设置向后依赖来使它不那么明显,例如:

public interface IOrderService
{
   //SomeOrderFunction()
   IPlanService planService;
}

....

public class PlanService: IPlanService
{
   private readonly IOrderService _orderService;

   public PlanService(IOrderService orderService)
   {
      _orderService = orderService;
      _orderService.planService = this;
   }
}

我尝试思考不同的方法,但最终计划需要建议无论是订单还是司机已更改。您认为这种方法如何,拥有一个了解所有服务的主节点。 http://blog.schauderhaft.de/2011/07/17/breaking-dependency-cylces/ - Kelsey Abreu
在我看来,这更像是一种变通方法,它还引入了时间耦合。 - jgauffin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接