Yan blurs the familiar notion of dependency injection types because it enables unlimited varieties of dependency injection method.
Primitive types of Dependency Injection
For the simplest form of dependency injection — Constructor Injection, java pseudo code is like:
A create(){
Object arg1 = instantiate 1st argument;
Object arg2 = instantiate 2nd argument;
...
return new A(arg1, arg2, ...);
}
Corresponding Yan code using auto-wiring is:
Component getCreator(){
return Components.ctor(A.class);
}
For another most frequenly used dependency injection — Setter Injection, java pseudo code is like:
A create(){
Object prop1 = instantiate 1st property value;
Object prop2 = instantiate 2nd property value;
...
A a = new A();
a.setProp1(prop1);
a.setProp2(prop2);
...
return a;
}
Corresponding Yan code with auto-wiring is:
Component getCreator(){
return Components.bean(A.class);
}
The pseudo code "instantiate ..." could involve further dependency resolutions for the argument/property and their dependents. So we use pseudo code to hide the complexity.
For simplicity, in the rest of this article (and in most of Yan documents), we use "..." to denote the series of "instantiate XXX". Whenever you see an occurence of "...", some dependency resolution code has to be in place. Hence, a Component or ComponentAdapter in Pico's terminology is needed.
So, the constructor injection pseudo code becomes:
A create(){
return new A(...);
}
And the setter injection pseudo code becomes:
A create(){
A a = new A();
a.set(...);
}
Dependency Injection in Yan vs. Pico
Next, we will compare some object creation logic in pseudo code and their corresponding way in Yan and Pico:
- Constructor Injection
- Pseudo Code:
A create(){ return new A(...); } - Yan:
Component getCreator(){ return Components.ctor(A.class) } - Pico:
ComponentAdapter getCreator(){ return new ConstructorInjectionComponentAdapter(A.class, A.class); }
- Pseudo Code:
- Setter Injection
- Pseudo Code:
A create(){ A a = new A(); a.set(...); return a; } - Yan:
Component getCreator(){ return Components.bean(A.class); } - Pico:
ComponentAdapter getCreator(){ return new SetterInjectionComponentAdapter(A.class, A.class); }
- Pseudo Code:
- Generalized Setter Injection
By "generalized", we mean that Java Bean setters are invoked on an object not created by the default parameter-less constructor.- Pseudo Code:
A create(){ A a = A.newInstance(...); a.set(...); } - Yan:
Component getCreator(){ Component a = Components.static_method("newInstance"); return a.bean(); } - Pico: BeanPropertyComponentAdapter looks like it. But you lose container-managed properties by using it.
- Pseudo Code:
- Factory Injection
- Pseudo Code:
A create(){ return A.newInstance(...); } - Yan:
Component getCreator(){ return Components.static_method(A.class, "newInstance"); } - Pico:
ComponentAdapter getCreator(){ return new FactoryInjectionComponentAdapter(A.class, A.class, "newInstance"); /*I did not find this ComponentAdapter in Pico's document, but it should be possible.*/ }
- Pseudo Code:
- Field Injection
- Pseudo Code:
A create(){ return new A(new B(...).age, ...); } - Yan:
Component getCreator(){ return Components.ctor(A.class) .withArgument(0, Components.ctor(B.class).field("age")); } - Pico: N/A
- Pseudo Code:
- Constructor then Factory
- Pseudo Code:
A.Sub create(){ return new A(...).createSubObject(...); } - Yan:
Component getCreator(){ return Components.ctor(A.class).method("createSubObject"); } - Pico: N/A
- Pseudo Code:
- Factory inside Factory
- Pseudo Code:
B create(){ return B.newInstance(A.newInstance(...), ...); } - Yan:
Component getCreator(){ Component a = Components.static_method(A.class, "newInstance"); Component b = Components.static_method(B.class, "newInstance") .withArgument(0, a); return b; } - Pico: N/A
- Pseudo Code:
- Local Singleton
- Pseudo Code:
B create(){ A a = new A(...); B b = new B(a, a, new A(...), ...); return b; } - Yan:
Component getCreator(){ Component a2 = Components.ctor(A.class); Component a1 = a2.singleton(); Component b = Components.ctor(B.class) .withArgument(0, a1) .withArgument(1, a1) .withArgument(2, a2); return b; } - Pico: N/A
- Pseudo Code:
- Array
- Pseudo Code:
A[] create(){ A a1 = new A(...); A a2 = A.newInstance(...); A a3 = new A2(...); a3.set(...); return new A[]{a1, a2, a3}; } - Yan:
Component getCreator(){ Component a1 = Components.ctor(A.class); Component a2 = Components.static_method(A.class, "newInstance"); Component a3 = Components.bean(A2.class); return Components.array(new Component[]{a1, a2, a3}); } - Pico: N/A
- Pseudo Code:
- Custom Collection
- Pseudo Code:
MyList create(){ A a1 = new A(...); A a2 = new A2(...); MyList ml = new MyList(); ml.add(a1); ml.add(a2); return ml; } - Yan:
MyList toMyList(Object[] arr){ MyList ml = new MyList(); for(int arr=0; i<arr.length; i++){ ml.add(arr[i]); } return ml; } Component getCreator(){ Component a1 = Components.ctor(A.class); Component a2 = Components.ctor(A2.class); Component arr = Components.array(new Component[]{a1, a2}); return arr.map(new Map(){ public Object map(Object a){ Object[] x = (Object[])a; return toMyList(x); } }; }
- Pico: N/A
- Pseudo Code:
- Dynamic Component
- Pseudo Code:
A create(ClassLoader loader){ Config config = new Config(...); String classname = config.getClassName("a"); Class impl = loader.loadClass(classname); Constructor ctor = impl.getConstructor(new Class[]{A.class, B.class}); return ctor.newInstance(...); }
- Yan:
Component getCreator(final ClassLoader loader){ Component config = Components.ctor(Config.class); return config.bind(new Binder(){ public Creator bind(Object c){ Config config = (Config)c; String classname = config.getClassName("a"); Class impl = loader.loadClass(classname); return Components.ctor(impl, new Class[]{A.class, B.class}); } }); }
- Pico: N/A
- Pseudo Code:
As you can see, Pico and Yan both support the primitive constructor/setter/factory injection. Yan goes out of her way to support much more varieties of dependency injection logic.
In fact, Yan completely eliminates the restriction on dependency injection types. "type 1", "type 2", "type 3" blah blah blah, these injection types set forth by other IOC containers really don't stand out in Yan any more. They are nothing more than a few primitive injection methods among thousands of injection types enabled by Yan — if we still want to call them "types".
