Follow treslines by email clicking Here!

Saturday, October 13, 2012

Understanding Dependency Inversion in real life


Hi there! Today i wanna share a real life example of dependency Inversion with you. In my RCP-Client developer career we had often the challange that due some customer change requests, we were forced to instantiate some domain specific dialogs from base. The problem here is that base (package: com.yourcompany.base) is not allowed to create dependencies to domain specific packages. So how could we solve this problem? We must inverse the dependency. What do we need? We will create a dependency registry in which we register domain specific dialog factories to be able to instantiate them from the base without having to create dependencies from base to specific domain packages.

The common factory interface

We define a factory interface in base. Let's say package is called: com.yourCompany.base.



interface DialogFactory{
    Dialog createFilterDialog();
}

In the same package we define an interface for the depencency inversion of our registry later:

// then we define also in base the interface for DependencyInversion in general. 
// to be used by all Registries we need in future. package: com.yourCompany.base
public interface DependencyInversion<T> {

    void registerFactory(String factoryMapKey, T factory);

    void unregisterFactory(String factoryMapKey);

    T getRegisteredFactoryOrNull(String factoryMapKey);
}

Now we need a Dependency Inversion Helper, which will handle the factory map later:


import java.util.HashMap;
import java.util.Map;

// for the same general reason, we define a dependency inversion helper which
// handle with the factoryMaps for any kind of factory in future. This class is
// also placed in base package: com.yourCompany.base
public class DependencyInversionHelper<T> {

    private Map<String, T> factoryMap = new HashMap<String, T>();

    public void unregisterIfExistsInMap(String factoryMapKey) {
        if (doesFactoryExistInMap(factoryMapKey)) {
            removeFactoryFromMap(factoryMapKey);
        }
    }

    public void registerIfNotExistsInMap(String factoryMapKey, T factory) {
        if (!doesFactoryExistInMap(factoryMapKey)) {
            insertFactoryIntoMap(factoryMapKey, factory);
        }
    }

    public boolean doesFactoryExistInMap(String factoryMapKey) {
        return this.factoryMap.containsKey(factoryMapKey);
    }

    public void insertFactoryIntoMap(String factoryMapKey, T factory) {
        this.factoryMap.put(factoryMapKey, factory);
    }

    public void removeFactoryFromMap(String factoryMapKey) {
        this.factoryMap.remove(factoryMapKey);
    }

    public T getRegisteredFactoryOrNull(String factoryMapKey) {
        return (T) (doesFactoryExistInMap(factoryMapKey) ? this.factoryMap.get(factoryMapKey) : null);
    }

}

The Registry

And finally we define in the same package our registry, which uses the helper and implements DependencyInversion:


// Now every thing we need to implement is the registry itself. This will be a singleton because
// we just need it once in the whole application. We place it also in base: com.yourCompany.base 
public class FilterDialogDependencyInversionRegistry implements DependencyInversion<DialogFactory> {

    private static FilterDialogDependencyInversionRegistry instance = new FilterDialogDependencyInversionRegistry();
    private DependencyInversionHelper<DialogFactory> helper = new DependencyInversionHelper<DialogFactory>();

    private FilterDialogDependencyInversionRegistry() {
        // singleton: we just need one global registry for it.
    }

    public static FilterDialogDependencyInversionRegistry instance() {
        return instance;
    }

    @Override
    public void registerFactory(String factoryMapKey, DialogFactory factory) {
        helper.registerIfNotExistsInMap(factoryMapKey, factory);
    }

    @Override
    public void unregisterFactory(String factoryMapKey) {
        helper.unregisterIfExistsInMap(factoryMapKey);
    }

    @Override
    public DialogFactory getRegisteredFactoryOrNull(String factoryMapKey) {
        return helper.getRegisteredFactoryOrNull(factoryMapKey);
    }

}

Ready for implementation:

Now we are able to register all factories we need with this registry. Because this registry is visible in base and in any other domain specific package, we can access our new Registry from anywhere and get the factory we need for any factoryMapKey we define. In Eclipse RCP this is usually done in the method  start() from the application. when the method getRegisteredFactoryOrNull(key) is called, we get a  DialogFactory and are able now to call the method createFilterDialog() from it. What it happens now is very cool. Any interface knows its implementation and creates the right dialog without having dependencies to the base modul. Any domain specific factory must only implement DialogFactory. That's all.

Advertising:
Optimized bets for playing EuroMillion's lottery on your Mobile Phone! 



No comments:

Post a Comment