Directly creating objects certainly is easy (examples in C#):
public class Consumer()
{
public void DoStuff()
{
var f = new Foo()
f.DoIt("bar");
}
}
While easy, it leads to tight coupling because you cannot vary the instance independently from the consumer.
While being more complex, a consumer using an Abstract Factory is loosely coupled:
public class Consumer()
{
private readonly IFooFactory fooFactory;
public Consumer(IFooFactory fooFactory)
{
if (fooFactory == null)
{
throw new ArgumentNullException("fooFactory");
}
this.fooFactory = fooFactory;
}
public void DoStuff()
{
var f = this.fooFactory.Create();
f.DoIt("bar");
}
}
This looks insanely more complex than the first version, but now you can vary the implementation of f
independently of Consumer
.
Not only will you be able to change the implementation, but you can also reuse or share instances between different consumers.
In many cases you don't need an Abstract Factory to enable loose coupling. Often, you can just inject dependencies directly into consumers instead of resorting to that extra level of indirection.