I have three classes which implement their interface.
Orders
public interface IOrderService
{
//SomeOrderFunction()
}
public class OrderService: IOrderService
{
//SomeOrderFunction();
}
Drivers
public interface IDriverService
{
//SomeDriverFunction()
}
public class DriverService: IDriverService
{
//SomeDriverFunction();
}
Plans -- Uses Driver and Plan services
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();
}
The issue I now have though is that the Order and Driver service need to talk back to the plan service when either an Order or Driver gets changed, how would I go about doing this without having a circular dependency?
Edit: Specifically I've been looking at creating a fourth service that manages all the other ones such as the one explained in this article.
Breaking Dependency Cycles
What confuses me about this implementation is my Plan class, does my plan class implement both the new class AND the IPlan interface?
via events.
create an event handler interface:
public interface IEventSubscriber<TEvent>
{
void Handle(TEvent evt);
}
then define an event:
public class PlanCreated
{
public int PlanId { get; set; }
//and other properties.
}
Now let one of the other classes implement it:
public class DriverService : IDriverService, IEventSubscriber<PlanCreated>
{
public void Handle(PlanCreated evt)
{
//handle it here.
}
}
now, to be able to publish events you need another interface:
public interface IEventPublisher
{
void Publish<TEvent>(TEvent evt);
}
Which can be invoked from your class:
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 } );
}
.. to invoke it we can use service location (implementation detail):
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);
}
}
}
}
.. as a result you get low coupling between the classes.
Inject a Func<IPlanService> instead of the IPlanService into the IOrderService and IDriverService. This 'breaks' the chain of instances that the container has to create.
public class OrderService {
public OrderService(Func<IPlanService> planServiceFactory) {
_planServiceFactory = planServiceFactory;
}
private readonly Func<IPlanService> _planServiceFactory;
public void SomeOrderFunction() {
_planServiceFactory().Notify(...);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With