This has been bothering me for a long time, and I could not find the right answer.
The Problem.
Imagine you have a factory interface (C# example):
interface IFooFactory
{
IFoo Create();
}
and it's implementation depends on a service:
class FooFactory : IFooFactory
{
private readonly IBarService _barService;
public FooFactory(IBarService barService)
{
_barService = barService;
}
}
where the service interface implements IDisposable
for a graceful shutdown:
interface IBarService : IDisposable
{
...
}
Now the actual class created by the factory has 2 dependencies - the service itself (passed through the factory), and another object that is created by factory:
class Foo : IFoo
{
public Foo(IBarService barService, IQux qux)
{
...
}
}
and the factory can create it like this:
class FooFactory : IFooFactory
{
public IFoo Create()
{
IQux qux = new Qux();
return new Foo(_barService, qux);
}
}
Finally IFoo
and IQux
both implement IDisposable
as well, so the class Foo
does:
class Foo : IFoo
{
public void Dispose()
{
_qux.Dispose();
}
}
But why do we dispose Qux
only on Foo.Dispose()
?
Both dependencies are injected and we just rely on the knowledge of exact implementation of the factory, where Bar
is a shared service (association relationship type) and the Qux
is used by Foo
exclusively (composition relationship type). It can be easy to dispose both of them by mistake. And in both cases Foo
logically does not own any of the dependencies, so disposing any of them seems wrong. Putting creation of Qux
inside Foo
would negate the dependency injection, so it's not an option.
Is there a better way to have both dependencies and make it clear what kind of the relationship they have to properly handle their lifetime?
Possible solution.
So here is one possible not that pretty solution:
class FooFactory : IFooFactory
{
private readonly IBarService _barService;
public FooFactory(IBarService barService)
{
_barService = barService;
}
public IFoo Create()
{
// This lambda can capture and use any input argument.
// Also creation can be complex and involve IO.
var quxFactory = () => new Qux();
return new Foo(_barService, quxFactory);
}
}
class Foo : IFoo
{
public Foo(IBarService barService, Func<IQux> quxFactory)
{
// Injected - don't own.
_barService = barService;
// Foo creates - Foo owns.
_qux = quxFactory();
}
public void Dispose()
{
// Now it's clear what Foo owns from the code in the constructor.
_qux.Dispose();
}
}
I'm not a fan of calling possibly complex logic in a constructor, especially if it's async
, and calling it on-demand (lazy load) can also lead to unexpected late runtime errors (vs. failing fast).
Does it really make sense to go that far just for the sake of the design? In any case I'd like to see if there any other possible elegant solution to this.