0

The problem / question.

I am trying to decouple as much as possible implementations and interfaces/abstract classes, in order to be able to switch implementations easily.

I learnt that the way to go was dependency injection, but before using a whole framework for that I would like to implement/understand the mechanism.

I also learnt that one way to implement dependency injection was to use abstract factories.

I am trying to use them in the following code, but I don't see where I get more decoupling between clients and implementations. I think I may not understand / implement the factory design pattern correctly to resolve this problem.

The sample situation

Let's say I have :

  • a mapper which is a generic interface :

    public interface Mapper<A,B> { [mapper methods]}

  • a concrete class that implements this mapper interface:

    JsonMapper implements Mapper<Json,ModelObject>{ [mapper methods implemented..] }

Now I want to use a mapper in a third object, a repository for instance :

OnlineRepo {
  // reference to an interface (which is good I guess)
  Mapper<Json, ModelObject> mMapper;

  // constructor needs a concrete Mapper<Json, ModelObject>
  OnlineRepo(Mapper<Json, ModelObject> jsonToModelMapper ){
    mMapper = jsonToModelObject;
  }

  // other OnlineRepo methods using mMapper, get, upsert etc etc...
  [...]
}

And finally my main code would have to instanciate the correct concrete classes. <- that's what I don't like.

main{
  JsonMapper mapper = new JsonMapper();  // reference to concrete JsonMapper

  OnlineRepo repo = new OnlineRepo(mapper); // inject concrete JsonMapper
}

How would the factory design pattern help me decouple these objects ?

  1. The OnlineRepository does not directly reference the concrete JsonMapper it references only the abstract Mapper<Json, ModelObject>. Isn't it ?

  2. How would an abstract factory design pattern help me decouple this code even more.

  3. It seems like I will always need to reference an implementation in my main program (if not an implementation of JsonMapper, an implementation of JsonMapperFactory ?).

To better illustrate I do not see the advantage of this :

psoeudo UML with abstract factory

over this :

psoeudo uml without abstract factory

What I would like to be able to do :

I would love to be able to do that in main (my client) :

Mapper<Json, ModelObject> = GenericMapperFactory.getMapper() And that would deliver a JsonMapper automatically.

I could also do things like Mapper<xml, ModelObject> = GenericMapperFactory.getMapper() and get the correct concrete object.

disclaimer

I hope my question is clear, if not, do not hesitate to tell me so I can work on it. These concepts are not yet completly clear for me so I have trouble writing clear an consise questions.

Thanks in advance for your help. Best, Antonin

Antonin
  • 879
  • 2
  • 10
  • 27

2 Answers2

1

The place where instantiate the concrete object is coupled to the created class. This is in your case the Main. By using the factory pattern you decouple your main from the implementation of the interface Mapper. You only know the Factory. Now subclassing the Mapper once again and using another kind of Mapper doesn't affect your main method.

Just to protect your Main from implementation classes I would not recommend the factory pattern. The Main is where your programm starts and thus responsible to create some objects and compose them together to bootstrap your application.

Factory should be either used when you create objects dynamically in your app or when you use some objects which are made to be used together (example: window factory (GUI))

If you create for example an application which can run with a Qt or a Cocoa GUI, you have to ensure the consistency between the frameworks. A QtFactory would create QWidgets and forms, whereas A CocoaFactory would create CocoaWindows. The rest of your application is decoupled from the used framework. If you instatiate a QtFactory in the main, your Programm would run with a Qt GUI, with a CocoaFactory it would be a Cocoa GUI. This this is the abstract factory pattern. It allows you to exchange implementation classes whithout to worry about if they would be mixed (Cocoa window with QWidget).

Janis
  • 1,020
  • 6
  • 14
0

The key point isn't using a factory or not but that you should use dependency injection with some inversion of control container. Hence, your repository instantiation will be done by the whole container and you'll leave your code absolutely agnostic to implementations.

Otherwise, if you do manual dependency injection, clearly you'll need to manually instantiate implementations.

For example, using an inversion of control container with dependency injection support, you would inject your repository and also you would either get the mapper's factory or the abstract mapper automatically:

public class WhoKnows
{
     public WhoKnows(IOnlineRepository repo)
     {
           // repo will come up with its dependencies already loaded
           // and its dependencies will also have their own dependencies already
           // loaded in cascade...
     }
} 
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • Thanks @Matías_Fidemraizer, but I though that abstract factory design pattern was a way to implement dependency injections. – Antonin Jan 21 '17 at 21:43
  • I though with such design pattern I would be able to centralize in a separate class the relation between interfaces and implementations. – Antonin Jan 21 '17 at 21:45
  • @Antonin No problem. Well, actually IoC containers have internal factories, right... Maybe I've not understood your question at all... When you talk about an abstract factory, are you trying to implement a factory to get implementations typed as interfaces/abstract classes, or an abstract factory of mappers? – Matías Fidemraizer Jan 21 '17 at 21:53
  • The goal was to remove strong dependency between the clients and the implementation (ie between repo or main and JsonMapper), and isolate that somewhere else so I can easily switch implementations. I'll try to fix my question to make it clearer (actually this is not clear in my head, hence the unclear question). – Antonin Jan 21 '17 at 22:24
  • @Antonin BTW I see that you're trying to reinvent the wheel, aren't you? Use an IoC container, you can't handle the complexity of implementing one and get similar results in few time... – Matías Fidemraizer Jan 21 '17 at 22:33
  • Certainly so Matias ;-) , I do it only once, to be sure I completely understand how it works then I'm ok to go with any IoC framework. My code being really simple I even could go with hard wired implementations all along but I am in a learning process. – Antonin Jan 21 '17 at 22:49
  • @Antonin You shouldn't go this route... It's like saying that you want to implement a GUI framework just because you want to learn how to implement GUI applications. My advise is you should go use a light-weight DI/IoC container like Ninject, see the wonders of DI and focus your learning on how to implement a proper separation of concerns, layering... – Matías Fidemraizer Jan 21 '17 at 23:01