I have a scenario where I think I am not strictly coding to an interface. Let's say I have an interface (in some assembly)
public interface IFoo
{
void GetSomething();
void SaveSomething();
}
Now, I have an implementation for this as (in some other assembly)
public class FoodB : IFoo
{
public FoodB(Guid guid, IFoodBConfig config) //IFoodBConfig is defined in same library where FoodB exists
{
...
}
}
So, basically the implementation requires guid and config
Now, I have a client (in some other assembly) that wishes to use IFoo
, something like
public class Client
{
public Client(IFoo foo)
{
...
}
}
DIP says that the implementation must be provided at composition root and the client must not instantiate the object itself. Alright great.
Now, composition root or IoC container decides to inject FoodB
as concrete instance but it doesn't have the value for 'guid' since that becomes available during runtime only.
So, we decide on an abstract factory.
public abstract FooFactory
{
public abstract IFoo GetFoo(Guid guid, IFoodBConfig config);
}
Now, several questions are raised
a) Client constructor must be modified to accept FooFactory
and not IFoo
which means the client has already made up its mind on what implementation to use. In my opinion this has made the software tightly coupled
b) Even if the Client constructor is modified to accept FooFactory
, IFoodBConfig
concrete must be supplied to constructor as well and this will now make client reference the library where FoodB
exists.
c) Where will the factory declaration and implementation be placed ? Putting FooFactory
in the library where IFoo
is declared is not correct since the factory has nothing to do with IFoo
. Putting FooFactory
in FoodB
library is also not correct because of the same reason
d) Using abstract factory in short means flexibility of swapping implementation has gone away since client is directory tied to FoodBFactory
.
Is the approach incorrect or this is some limitation that we have to live with ?
Several points to address in this question.
FooFactory
is not an example of an Abstract Factory
, at least by the GoF terminology.Abstract Factory
!= abstract class named Factory.a) As @dbugger commented, coupling the client to an abstract class is no different from coupling to an interface.
b) Either the FooBFactory
implementation or the IoC container can be pre-configured with FooBConfig
. The client then only passes its runtime guid.
c) FooFactory
is directly related to IFoo
because its purpose is to return an instance of IFoo
. Indeed, the return type of its method is IFoo
.
d) Flexibility exists because an IoC container can inject different implementations of a Factory Method into the client, allowing the client to acquire different products without having knowledge of either the product implementation or the factory implementation used to instantiate it.
If you're comfortable coupling the client to the IoC container, the client can use the container directly as a factory, eliminating the additional factory interface.