0

I am using DI to pass around my dependencies. But in some scenarios we need to create objects dynamically and do need to provide parameters during initialization. Code sample -a tries to explain the scenario.

In order to initialize such type of objects and hide new operator, I created simple factories. Code sample -b.

Code sample -a

int are used for simplicity they will/can actually be some real objects

public class Sample {

    private final int c;
    public Sample(int c){
        this.c = c;
    }

    public void doSomething(SomeCommand command, Request request, Context context){
        DynamicDependency dynamicDependency = new DynamicDependency(command.getA(), command.getB(), c);
        dynamicDependency.doSomeWork(request, context);
    }

}

class DynamicDependency{

    private final int a;
    private final int b;
    private final int c;

    public DynamicDependency(int a, int b, int c){

        this.a = a;
        this.b = b;
        this.c = c;
    }

    public void doSomeWork(Request request, Context context){
        /*
        Do work
         */
    }
}

class SomeCommand {
    private int a;
    private int b;

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }


    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }
}

Code sample -b

public interface IParameterizedObjectFactory<T> {
    T getInstance(Object... arguments) throws ClassCastException;
}

public class DynamicDependency implements IParameterizedObjectFactory<DynamicDependency> {

@Override
public DynamicDependencyFactory getInstance(Object... arguments) throws ClassCastException {
        Validate.notNull(arguments);

        if(arguments.length > 0){
            final int a = (Integer) arguments[0];
            final int b = (Integer) arguments[1];
            final int c = (Integer) arguments[2];
            return new DynamicDependency(a, b,c);
        }
        return null;
    }
}

This does the job as I can now inject factory and then use it to get the new object as:

DynamicDependency dynamicDependency = dynamicDependencyFactory.getInstance(a,b,c);

Question(s):

Though, it does the job but we need to pass around list of Object[s] and and we loose strong typing. Casting also will eat up some execution time. How can it be improved?

Another approach could be to not to use the interface at all and use concrete classes which have getInstance method with appropriate parameter list. Sounds reasonable to me.

public class DynamicDependencyFactory {

    public DynamicDependency getInstance(int a, int b, int c) {
        return new DynamicDependency(a, b,c);
    }
}

What else can be done to hide new? Or should I use second approach to create concrete factories?

Note: I am trying to stay away from reflection

Anuj Yadav
  • 980
  • 11
  • 20
  • "Casting also will eat up some execution time"? – Kayaman Sep 23 '16 at 15:58
  • @Kayaman I meant casting from Object type to actual type will have some overhead. – Anuj Yadav Sep 23 '16 at 16:01
  • 1
    [Factories are a code smell](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=100), [runtime values should not be injected into a component's constructor](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99). – Steven Sep 23 '16 at 16:05
  • @AnujYadav Any overhead introduced by casting is completely irrelevant to this question. – Kayaman Sep 23 '16 at 16:07
  • @Steven Nice articles. Yes, I follow this approach in general. I forgot to mention that this is a legacy application and just wanted to avoid big refactoring. But I may consider now, after reading the articles :). May be a bit more work for better quality. – Anuj Yadav Sep 23 '16 at 16:54
  • @AnujYadav do you use some standard DI framework (like Spring DI or Guice) or custom made? Any standard DI framework has ability to work not only with singleton objects but also with prototypes. DI creates a new instance of a prototype class during any new injection. – Andriy Kryvtsun Sep 23 '16 at 18:36
  • @AndriyKryvtsun yes we are using but runtime values are not something which DI will help with. And also there are multiple scenarios as explained below in the answer. – Anuj Yadav Sep 23 '16 at 19:09
  • @AnujYadav pls, specify your DI framework and I'll create solution compatible with it with your needs. – Andriy Kryvtsun Sep 23 '16 at 19:10
  • @AndriyKryvtsun We are using Spring DI. But we do have modules where we do not use any DI framework but only core Java. Those modules are part of our framework which is used by non Spring based applications as well. – Anuj Yadav Sep 23 '16 at 19:17
  • @AnujYadav I would not to reinvent a wheel and use Spring `prototype` approach like in this answer this http://stackoverflow.com/q/22155832/2313177 – Andriy Kryvtsun Sep 23 '16 at 20:54

2 Answers2

0

I decided to go with a mixed approach, using factories where I do not have control on the runtime object being created and passing runtime data via methods where the control is with me.

Steven shared couple of good articles in the comments, posting here.

Factories are a code smell runtime values should not be injected into a component's constructor

Fortunately I was already avoiding the constructor injection in case of runtime values. The problem was with the legacy code and the code which is not owned by our team. For now, for the code which is not owned by us we have to use constructor even though it will smell a bit :)

Anuj Yadav
  • 980
  • 11
  • 20
0

The second approach you suggested is much better than the first. You still have the option to extract an interface from that factory if required:

public interface IDynamicDependencyFactory {
    DynamicDependency getInstance(int a, int b, int c);
}

Note the lack of generic type parameters. Your first suggestion of the following interface:

public interface IParameterizedObjectFactory<T> {
    T getInstance(Object... arguments) throws ClassCastException;
}

seems completely unnecessary according to your example, and, as you have noted, the Object[] as the arguments makes it a very unpleasant and non-type safe API to work with.

If you really need to pass different argument types to the methods on the factory, then define an overload for each valid signature instead of just accepting an Object[]:

public interface IDynamicDependencyFactory {
    DynamicDependency getInstance(int a, int b, int c);

    DynamicDependency getInstance(double a, int b, BigDecimal c);
}

Better yet, if you can refactor your code so that it does not require such a factory then that could be beneficial (unless you do not have access to the Request and Context objects at the same time as the a, b, and c int values). For example, you can pull up the constructor arguments to be method parameters and treat your DynamicDependency more like a service (or singleton):

class DynamicDependencyService {
    public void doSomeWork(Request request, Context context, int a, int b, int c){
        //Do work
    }
}

This way, an instance of DynamicDependencyService can be passed to your Sample object via the constructor.

tonicsoft
  • 1,736
  • 9
  • 22
  • There are multiple scenarios. Major problem is where we do not have control over the APIs. The code which do not own. Smell lies there. Thus, at few places we will have to use factories. Yes, I am going with concrete classes instead of Object[] based interface. – Anuj Yadav Sep 23 '16 at 19:06