|
Sponsored Links
Resources
Enterprise Java Research Library
Get Java white papers, product information, case studies and webcasts
|
News
News
News
|
Messages: 56
Messages: 56
Messages: 56
Printer friendly
Printer friendly
Printer friendly
Post reply
Post reply
Post reply
XML
XML
XML
|
 |
Opinion: Why I prefer constructor-based dependency injection
Simon Harris has written an opinion piece on why he prefers constructor-based dependency injection, compared to the set*() method approach. The main point revolves around "restricting the number of parameters you may declare for a method".
Excerpt"On the current project I'm on, and no doubt on many of yours, we have restrictions on the number of parameters you may declare for a method. This, hopefully, forces developers to re-evaluate what they are passing around. For example, use a DateRange instead of dateFrom and dateTo.
Unfortunately there is a simple way to subvert that process by simply declaring everything as "setters" which typically have only one parameter. Then all the lovely detail becomes much harder to see as it's hidden in the morass of the aptly name mutators (yet another reason I dislike getters and setters).
Declaring service dependencies in constructors allows me to see them all in one go. It immediately becomes apparent if a class depends on "too many". Something that is much harder to see when you use setters. It also allows us to construct objects in a valid state with all the obvious benefits.
Another advantage to using a constructor is that only the creator need know about the dependencies. In our case it's our ServiceRegistry. Once an object has been constructed (either by the registry configuration for singleton services defined by interfaces or by calling ServiceRegistry.newInstance(Class) allowing the construction of any class that depends on a service) client code is unaware of the dependency." Read Simon Harris in Why I prefer constructor-based dependency injection
ps. Check out the interesting comments
|
|
Message #118585
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Opinion: Why I prefer constructor-based dependency injection
I found constructor-based dependency injection bad choice when you have class hierarchies of the componenets (beans, POJOs, etc...). Passing all the parameters to the super method is a boring bloat and error prone. Also setter based dependency injection has its downsides too.
I found that for classes that need to be configure with a lot of parameters and which need reconfiguration facility, the following dependency injection pattern is prefreable:
- create a separate configuration bean (named XXXComponentConfig for example) consisting of all rquired configuration parameters for you component (named XXXComponent). The been itself should be populated with setter methods for easier subclassing. - provide a configure method in your component: public void configure(XXXComponentConfig config);
Whether your XXXComponent will store a reference to XXXComponentConfig instance or will store all configuration properties separately is implementation specific.
The advantages of this approach are following: - your component is reconfigurable (important in dynamic environments) as oposed to constructior dependency injection which is not well suited for reconfiguration. - your component is configured in one method (in one place), thus more readable then setter based dependency injection. - configure method can be synchronized thus providing the consistency to the component configuration state (when reconfiguring), as oposed to setter based dependency injection which cannot easily be reconfigured without sacrifacing consistency of the configuration state.
I do not know if there is a name for this dependency injection approach.
Mileta
|
|
Message #118588
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Opinion: Why I prefer constructor-based dependency injection
I used to prefer constructor based initialisation but the problem comes when your object grows to need a new property. If you provide a sensible default then your contract with the original code is unchanged. Otherwise you must update the constructor and also update every piece of code that uses the object. Then you have to regression test it.
I have finally come back to the conclusion that default constuctors and getters/setters are better.
Constructor based intialisation should still be used when the order of initialisation matters but for simpel objects this does not apply.
|
|
Message #118590
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Other benefits to constructor-only
There are other benefits to using the constructor rather than set methods (cue Effective Java style rant) - it means you can maximise the number of immutable objects. Saying that it makes inheritance more difficult is not such a big problem if you're using data objects - mostly you end up using composition rather than inheritance anyway.
Of course as usual it all depends what you're trying to do...
|
|
Message #118591
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
And another thing...
Oh yeah, and I forgot to add, it makes exception handling neater, since all your data validation happens in the constructor.
|
|
Message #118594
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructors too Constricting
Come on, guys, I really appreciate the value of immutability and all, but it takes about ten minutes of actual work to see the limitations of contructor-based dependency injection.
Try:
public TaxBasis( String customerId )
and
public TaxBasis( String companyId )
Uh... OOPS! I'm sure that there are some people that will advocate refactoring my dependencies and creating artifical construction signatures to try and avoid duplication. No, thank you. I am willing to sacrifice some level of immutability (or introduce an extra instance variable to enforce it if necessary) to avoid redesigning my architecture around the technical limitations of constructors.
|
|
Message #118596
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Opinion: Why I prefer constructor-based dependency injection
I used to prefer constructor based initialisation but the problem comes when your object grows to need a new property.If you provide a sensible default then your contract with the original code is unchanged.Otherwise you must update the constructor and also update every piece of code that uses the object. Then you have to regression test it.I have finally come back to the conclusion that default constuctors and getters/setters are better.Constructor based intialisation should still be used when the order of initialisation matters but for simpel objects this does not apply. This is a + for constructor-based dependency injection IMHO. If there's no good choice for a default value, you just change the constructor and you'll get an exception when your application. If you simply add a new setter you'll need to remeber to change your configuration files.
|
|
Message #118597
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
OO Without Inheritance
My counter to this is simple: don't have deep and/or wide class hierarchies. I rarely find the need for them and they're usually a code smell.
Aaargh! This is what always annoys me: "If you have a valid issue with [technical approach that I am advocating], the problem is actually with your design. I have never seen your project before, but I can tell you that you need to redesign your architecture to work around the non-existent limitations of [technical approach that I am advocating]."
When you work on enterprise systems of a certain size of reasonably complex business logic, deep or wide class hierarchies are not a bad code smell. They are almost always necessary to eliminate bad code smells, particularly cut-and-paste code across large number of classes and poor readability.
General advice: If you are convinced that X technology is perfect, but the problem lies with people who use inheritance, or require multithreading, or need to keep more than 32 megs of data in memory at a time, or who need a throughput of greater than 2 transactions per second, the problem may actually lie with technology X.
|
|
Message #118598
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructor Syntax
Try:
public TaxBasis( String customerId )a
and
public TaxBasis( String companyId ) Actually this won't compile. You can't have two constructors with the same signature. The type or number of parameters has to be different. Perhaps this was a typo?
|
|
Message #118599
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Opinion: Why I prefer constructor-based dependency injection
I see both ways have limitations, probably one of good ways to configure app is to configure it without any injection.
|
|
Message #118602
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructors too Constricting
The method I descirbed (the separate configure method with XXXConfig bean) has 'the best of both worlds' (best of the setter injection and the constructor injection approaches): Pros: - configuration is held in one plase (XXXConfig bean) and is separate from other instance fields of our component which are not configuration specific. - configuration process is done at one place, thus easily synhronized. - reconfiguration is easy. - exception handling is easy. - configuration order is maintenable. Cons: - separate config class is required. But, this may not be a con. because you anyway has to provide getters to access the configuration attributes in the component class for setter and constructor based injection.
Mileta
|
|
Message #118604
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructor Syntax
Actually this won't compile. You can't have two constructors with the same signature. The type or number of parameters has to be different. That was my point. This is one of the limitations introduced by contructor-based injection.
|
|
Message #118605
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Silliness
'Constructor-based dependency injection' has to be one of the silliest phrases I've heard in a while. Why not just call them 'constructors'? Seriously, this emperor has no clothes. Constructors aren't for 'declaring service dependencies' either. It is a seriously bonehead thing to do; it's a brittle, non-OO hack. Constructors should initialize an object into some known state and that's it. Trying to force them to do anything else is just wrong. It's really that simple. Also, two more things. Using a ServiceRegistry to construct all your objects (a la Spring) is a serious anti-pattern. As your codebase grows the SR just becomes more and more complex (a la Spring). This kind of centralization also confuses things since you literally have to decode how an object is being constructed. Finally, passing instances of the SR around (or using a static singleton) If object A needs to construct B and you need to hide B's configuration logic from A then use a Factory. On the other hand, giving a bean a configure(Config) method also seems like a bad idea. More than likely you want (1) the State pattern to completely externalize the parameters (2) the Prototype pattern so constructing an object is as simple as cloning it and then customizing it with a few setters (3) the factory pattern.
|
|
Message #118606
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructor Syntax
Try:public TaxBasis( String customerId )aandpublic TaxBasis( String companyId ) Actually this won't compile. ... Voila !
|
|
Message #118607
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructor Based Dependency Injection
For me the advantages of constructor based injection come down to the following:
1. Immutable objects. Not possible with setters. 2. No temporal coupling. Once constructed, the object is good to go. 3. No need to change my code for the sake of the container.
OK, #3 cuts both ways. If used aggresively, immutable objects can eliminate a whole category of bugs, and simplify (or to be precise, make unnecessary) copying/cloning. It would annoy the heck out of me if I had to add setters to all my immutable objects for the sake of the container. Since I try to avoid #2, most of my classes do have constructors that take all the dependencies.
But of course there are exceptions, especially with code you don't control or objects you don't instantiate (i.e. Struts actions). So both styles need to be supported, but I always reach for constructor injection first.
|
|
Message #118608
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Silliness
>> More than likely you want (1) the State pattern to completely externalize the parameters (2) the Prototype pattern so constructing an object is as simple as cloning it and then customizing it with a few setters (3) the factory pattern.
I think you miss the point about dependency injection. The dependency injections is all about moving configuration state handling OUT of your business logic components. With dependency injection you do not have to write code to read from configuration file (or other configuration state sources) because it is generic and already implemented in the container. Also constructor dependency injection and 'configure method injection' clearly separates configuration state from other component state that may or may not be transient.
|
|
Message #118610
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Silliness
Agree, it is an antipattern. Probably some comprimise like "init.js/destroy.js" scripts can be a good way to configure "global" objects.
|
|
Message #118611
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Missed my morning coffee dependency injection
Ah, sorry. Haven't finished my morning coffee yet.
Good point. In cases like that, I still don't rely on the client invoking a setter. Instead I create two static factory methods:
class TaxBasis { public TaxBasis createCustomerTaxBasis(String customerId); public TaxBasis createCompanyTaxBasis(String companyId);
private TaxBasis() {} }
That ensures that the object is always created in a valid state, and I can make it immutable if I want to. But of course this won't work with either style of dependency injection. Perhaps we need 'static factory method based injection'?
In this particular case, perhaps Customer and Company need to be explicit types. I.e.:
public TaxBasis(Customer customer);
public TaxBasis(Company company);
If you have two different constructors with the same signature, it could be a sign of a missing type (or subclass). But not always. And of course one shouldn't have to redesign one's code for the sake of the container (either by adding setter methods or an artificial constructor).
I'm not arguing that a container shouldn't support setter based injection. But for me at least, constructor based injection is less invasive. I'd have to change more of my code to support the container with setter based injection, than I would with constructor based injection. So I reach for constructor based injection first, and only use setter injection when that doesn't work (usually with objects I don't control and don't instantiate.)
|
|
Message #118612
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructor Based Dependency Injection
It would annoy the heck out of me if I had to add setters to all my immutable objects for the sake of the container. Good point. The container should not enforce its world view on you: If you prefer constructor injection, there should be non-intrusive ways to apply it. On the other hand, there might be objects that naturally have bean properties with setters (for example because of numerous optional settings); the container should provide sophisticated means for initializing those too. It's all about choice (true choice, that is, not checked options for marketing purposes).
Juergen
|
|
Message #118613
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
RE: Missed my morning coffee dependency injection
Meant to make the factory methods static:
class TaxBasis { public static TaxBasis createCustomerTaxBasis(String customerId); public static TaxBasis createCompanyTaxBasis(String companyId);
private TaxBasis() {} }
Still haven't finished my coffee.
|
|
Message #118615
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructor Based Dependency Injection
<blockquoteThe container should not enforce its world view on you: If you prefer constructor injection, there should be non-intrusive ways to apply it. On the other hand, there might be objects that naturally have bean properties with setters (for example because of numerous optional settings); the container should provide sophisticated means for initializing those too. It's all about choice (true choice, that is, not checked options for marketing purposes).JuergenCouldn't agree more! I think (hope) that the discussion here is about which to reach for first, constructor or setter DI, and which situations call for one approach over the other. There are definitely cases where constructor injection is more than a preference; often it's the only way to achieve a sound design with immutable objects and no temporal coupling. But sometimes the reverse is true and you do need setter injection.
|
|
Message #118616
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Missed my morning coffee dependency injection
Instead I create two static factory methods: (...) That ensures that the object is always created in a valid state, and I can make it immutable if I want to. But of course this won't work with either style of dependency injection. Perhaps we need 'static factory method based injection'? Spring provides means to invoke static factory methods via its MethodInvokingFactoryBean class, offering the method invocation result for bean references: A collaborating object just needs to expose a constructor argument or bean property setter of the result type.And of course one shouldn't have to redesign one's code for the sake of the container (either by adding setter methods or an artificial constructor). Completely agreed. A container should support your style of development (as far as possible) rather than enforce its own, and allow for easy migration between different styles.
Juergen
|
|
Message #118623
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Question...
Pardon the possibly ignorant question, but why the concern for immutability. Is this a problem with our service objects? Take this code for example:
public class SomeWebLayerThingy { private SomeServiceInterface service; public void setSomeServiceInterface(SomeServiceInterface service) { this.service = service; } // code that does stuff goes here }
Why should SomeWebLayerThingy be concerned that its instance of SomeServiceInterface is immutable. Shouldn't it just be concerned that it just does its job?
Also, couldn't immutability of service ojbect be a bad thing? What if we have a CacheProvider interface that provides some properties to "tune" the cache. Let's say the load of our application has been growing significantly and we want to expand the size of the cache. Why shouldn't we be able to have a way (JMX?) to call setCacheSize on our CacheProvider at run time, thus mutating our CacheProvider service object. Provided that that CacheProvider implementation handles that run time change robustly, any of the CacheProvider clients will be using a mutable bean.
This is a simplified example, but I can see a real use case for this. Perhaps I am missing something. I can see the use for immutability for value objects that comprise our model - we don't want outsiders mucking with our data without notifying our objects:
someBean.setDate(date); // setDate does not make a defensive copy! date.setTime(0L); // oops!
But service objects that do not offer a means to manage their properties except through a constructor seems limiting to me.
Ryan
|
|
Message #118627
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructors too Constricting
The method I descirbed (the separate configure method with XXXConfig bean) has 'the best of both worlds' It also suffers from a few fatal flaws:
- All that you have accomplished is push back the problem further (now it's your Config beans that needs to validate your arguments and not your real class).
- If the business logic in your real class changes its semantic or adds a new parameter, you need to remember to update your Config class as well (and no static typing nor refactoring will help you there, you are completely on your own).
Your code has just become a lot more fragile and harder to maintain.
-- Cedric http://beust.com/weblog
|
|
Message #118630
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Missed my morning coffee dependency injection
In this particular case, perhaps Customer and Company need to be explicit types. I.e.: public TaxBasis(Customer customer); public TaxBasis(Company company); I think you are missing the point. How do you cover the following case with constructor-based injection:
public TaxBasis(Customer payingCustomer); public TaxBasis(Customer invitedCustomer);
?
If you have two different constructors with the same signature, it could be a sign of a missing type (or subclass).
Once again, there is simply no silver bullet. You have three choices:
- Constructor-based injection - Setter-based injection - No injection (default constructor and invoke setters yourself)
All three have their use and if you tell me you should only ever use one of them, I am sure I can come up with an example to prove you wrong :-)
-- Cedric http://beust.com/weblog
|
|
Message #118632
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Question...
We might be talking about two different things - but I'm not sure if I understood you correctly. The issue is whether the *client* of the service (SomeWebLayerThingy) can be immutable or not. The service itself could have set methods, or not. But if you use setter based injection to supply SomeWebLayerThingy with its SomeServiceInterface, then SomeWebLayerThingy has to have a setService method. You can't make SomeWebLayerThingy immutable.
Now maybe you don't want to make SomeWebLayerThingy immutable. Obviously not everything can or should be immutable. But with setter injection, you don't have a choice. You just can't make it immutable. Construction injection works with both mutable and immutable objects. You can remove the set methods later and your still OK.
Setter injection can introduce a subtle dependency on the container. The setter methods have to be there for the container to do its magic.
|
|
Message #118633
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructors too Constricting
>> - All that you have accomplished is push back the problem further (now it's your Config beans that needs to validate your arguments and not your real class).
I do not see what is the problem with this. The basic validation could be done by the container (based on property type). If you need more sophisticated validation you can write it in configure method of the main component of in the config bean itself.
>> - If the business logic in your real class changes its semantic or adds a new parameter, you need to remember to update your Config class as well (and no static typing nor refactoring will help you there, you are completely on your own).
If you keep the reference to the config bean in you main component you do not have to duplicate configuration properties twice.
Mileta
|
|
Message #118639
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Question...
Actually, in my example I was talking about making the service immutuable. I'll go back the CacheProvider example. Let's say our CacheProvider is really simple and has one property - size. If we are going to manage this CacheProvider with an IoC container, we can set the size two ways - by constructor or by setter. An argument for constructor injection is that when I instantiate my CacheProvider implementation by passing my cache size, it is now it a valid state and (if no setCacheSize method) immutable.
My question is, why is this good? Is mutablility bad? Why? To me, it seems that immutability eliminates run time configurability. Again, I can see the value for mutability for value object. I don't see it buying much in the realm for dependency management. In a well behaved application, I can't see the fact that my object's dependencies are mutable will ever get me into trouble.Setter injection can introduce a subtle dependency on the container. The setter methods have to be there for the container to do its magic. How is this different than constructor injection? *Something* has to create/inject the object in either scenario. The fact that the container has to instatiate and inject separately in the setter case is really of no concern to me. As long as the container allows me an easy way to express my dependencies, I don't see much difference (auto wire rocks here!).
The other question I have is what to you do with components that have lots of configurable properties, like a connection pool. Do you have many constructors? One monolythic constructor? What if there are twelve different configurable properties for a service (very possible for a connection pool - min/max connection, idle time, user name, password, URL, driver, etc). A twelve argument constructor would look a little unwieldly, no?
Ryan
|
|
Message #118647
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Question...
An argument for constructor injection is that when I instantiate my CacheProvider implementation by passing my cache size, it is now it a valid state and (if no setCacheSize method) immutable. The first argument, guaranteeing the service is in a valid state, still applies even if you don't require immutability. Well, not if the only dependency is 'size'; the default no-arg constructor could just fill in the default. But sometimes services depend on other services. Supplying dependent services in the constructor guarantees that the object is created in a valid state, even if you do allow clients to change parameters afterwords.
I don't think anyone is arguing that mutability is always a bad thing. But it's nice to have the immutability option. I actually do make most services immutable, and only configurable at creation time. But of course there are exceptions.
Take a DAO service. I usually don't want clients swapping out SQL strings, data sources, etc. at run time, after the object is created. At creation time sure, but after that usually no. I could imagine cases where I would want that, but usually I don't. And when I don't, it's safer and provides a smaller interface to make those properties immutable.
If you need to supply 12 constructor parameters to support construction injection, sure that's a pain. Maybe you reach for setter injection in that case. But configuring those 12 parameters in the container config is going to be a pain too. Maybe things need to be refactored and broken up a bit.
I'm not saying there's never a need for setter injection. But when you do need setter injection, it's often, *but not always*, an indication of a code smell.
Steve
|
|
Message #118648
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructors too Constricting
>> - All that you have accomplished is push back the problem further (now it's your Config beans that needs to validate your arguments and not your real class).
I do not see what is the problem with this. Now you have two classes to keep in synch.If you keep the reference to the config bean in you main component you do not have to duplicate configuration properties twice.Mileta I think you missed my point.
Imagine that you create a PersonConfig to create a Person. One day, you decide that on top of firstName and lastName, a Person needs to be created with a socialSecurityNumber as well, and that it's mandatory.
You add this field to Person but you need to remember to add it to PersonConfig as well or your code will break.
You are duplicating your work all over the place, as opposed to keeping the validating logic inside Person, where it belongs.
-- Cedric
|
|
Message #118653
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Missed my morning coffee dependency injection
I'm not arguing that constructor based injection is a silver bullet. There are certainly cases where setter based injection is more appropriate. But I think the point the author of the article was trying to make is that he finds construction injection *preferable". I think construction injection should be ones first choice. Coming up with examples of where constructor injection doesn't work does not invalidate that preference / recommendation. I think you are missing the point. How do you cover the following case with constructor-based injection:
public TaxBasis(Customer payingCustomer);
public TaxBasis(Customer invitedCustomer); I think I got the point. (I've had my coffee now. ;) ) Again, I think introducing creator factory methods would be preferable to introducing setter methods:
public static TaxBasis createForPayingCustomer(Customer customer);
public static TaxBasis createForInvitedCustomer(Customer invitedCustomer);
The explict names remove any ambiguity, and the object is constructed in a valid state.
I guess you would need to use something like Spring's MethodInvokingFactoryBean for this. This seems like a variation on constructor injection to me, working around the fact that Java doesn't have named constructors.
|
|
Message #118654
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Missed my morning coffee dependency injection
>Spring provides means to invoke static factory methods > via its MethodInvokingFactoryBean class, offering the > method invocation result for bean references
Why do you need spring at all to do such a simnple thing? If you have service accessors then whomever constructs an object can just pass in the correct references. There's no need for a separate confusing framework.
|
|
Message #118658
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
temporal resolution is an issue
Not all services are available at the time of construction or stay valid during the life time of an application, or i would say always use construction based configuration because it is the simplest, clearest, most obvious approach.
By temporal resolution i mean an application may have a dependency tree of service references that can only be satisfied by the running of multiple state machines that can't run prior to construction.
Applications that have distributed forms of calculations have the issue all the time. As an application i need to provide different sets of services at different points in my state machine. In each state i need different other services to provide my services. Thus they can't be satisified only at construction.
|
|
Message #118666
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Opinion: Why I believe it is not serious...
We found that the biggest value of IoC design is usually attained when dealing with legacy objects, something that was created before and needs to be integrated into new or another application. In many cases to use these objects you will need to:
- Create object with constructor
- Set certain JavaBean and non-JavaBean properties into it
- Call one or several initialization methods with various signatures
...and after that object is considered logically created and initialized. To support this behavior we had to come with much more advanced IoC implementation, one that has generalized invocation capability additionally to ctor-based injection.
Regards, Nikita Ivanov. xTier - Service Oriented Middleware
|
|
Message #118667
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Missed my morning coffee dependency injection
I guess you would need to use something like Spring's MethodInvokingFactoryBean for this. This seems like a variation on constructor injection to me, working around the fact that Java doesn't have named constructors. Pico container allows registering component factories by using ComponentAdapters if necessary. They can call static methods, work as cache, or return cached proxies of an object and switch implementations at rintime.
|
|
Message #118671
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Opinion: Why I prefer constructor-based dependency injection
I used to prefer constructor based initialisation but the problem comes when your object grows to need a new property. If you provide a sensible default then your contract with the original code is unchanged. Otherwise you must update the constructor and also update every piece of code that uses the object. Then you have to regression test it.
If you use getters / setters, you'll either need to: -provide sensible defaults, because the setter won't be called. -find all statements that create an instance of that class, which is much more likely to be done wrong, as the compiler won't complain.
|
|
Message #118674
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Missed my morning coffee dependency injection
Good point.
One of the things I like about PicoContainer is the ComponentAdapter concept. As soon as you say "You can't do 'X' in Pico," you soon realize that you can quickly write a little ComponentAdapter to do 'X'! They're very easy to write.
PicoContainer has a very clean, minimalistic, elegant and extensible design.
(Which is not do say that Spring doesn't! Don't want to start a flame war; I'm just more familiar with Pico's design.)
|
|
Message #118689
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Missed my morning coffee dependency injection
>Spring provides means to invoke static factory methods > via its MethodInvokingFactoryBean class, offering the > method invocation result for bean references. Why do you need spring at all to do such a simnple thing? If you have service accessors then whomever constructs an object can just pass in the correct references. There's no need for a separate confusing framework. The point is that this mechanism allows you to pass the factory method result to constructor arguments or property setters of other components in a declarative fashion. Of course, you can invoke the factory method yourself and do whatever you want with the returned object, but then you implement programmatic configuration code which depends on a specific factory method. Not to say that this is a bad thing in general, but it is not what IoC is about.
As a side note, MethodInvokingFactoryBean is just a convenience implementation of the FactoryBean interface, which is Spring's generic mechanism to plug in *any* object into its IoC wiring namespace. Other examples are JndiObjectFactoryBean and LocalSessionFactoryBean, looking up a specific JNDI object respectively setting up a local Hibernate SessionFactory instance.
FactoryBean is a simple interface: If you have some object that needs special setup, implement a FactoryBean for your custom needs, exposing the desired object via the getObject() method. You'll then configure the FactoryBean as Spring bean definition, which will expose your desired object for bean references rather than itself - the main characteristic of a FactoryBean.
Juergen
|
|
Message #118714
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
OO Without Inheritance
"When you work on enterprise systems of a certain size of reasonably complex business logic, deep or wide class hierarchies are not a bad code smell. They are almost always necessary to eliminate bad code smells, particularly cut-and-paste code across large number of classes and poor readability. I couldn't disagree more. Reuse by inheritance is in my experience a much poorer form of reuse than that of delegation.
With a delegation model you have the flexibility of dynamic composition, whereas with inheritance you are statically bound to the class hierarchy.
You can have a lot more fun with a Wallet that has-a Currency than a DollarWallet that is-a Wallet.General advice: If you are convinced that X technology is perfect, but the problem lies with people who use inheritance, or require multithreading, or need to keep more than 32 megs of data in memory at a time, or who need a throughput of greater than 2 transactions per second, the problem may actually lie with technology X. That's unfair. Technology is not a remedy for bad design. However, Good design is an enabler for good code.
|
|
Message #118716
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructors too Constricting
Cedric,
With a non dependency injection scheme (Wallet creates Currency rather than having it injected)..
.. How do you test the Wallet in isolation (without dragging along a concrete implementation of Currency)?
I'm a bit disappointed that the testing aspect of CDI has been completely ignored in this thread.
In fact, CDI is closely related to TDD and mocking and they all complement each other. I'm not saying that you should all go out and use this happy trio, but those of you who do will have a pleasant surprise.
|
|
Message #118717
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
OO Without Inheritance
I couldn't disagree more. Reuse by inheritance is in my experience a much poorer form of reuse than that of delegation. I can agree with this, in cases where inheritance or composition/delegation are equally capable of solving the problem. But my experience is that for complex problems, delegation works better for 'wide' hierarchies, and inheritance works better for 'deep' hierarchies.That's unfair. Technology is not a remedy for bad design. No, what's unfair is making dismissive statements like 'all inheritance is bad design' in order to justify a particular technical advocacy position.
|
|
Message #118718
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
OO Without Inheritance
I couldn't disagree more. Reuse by inheritance is in my experience a much poorer form of reuse than that of delegation.With a delegation model you have the flexibility of dynamic composition, whereas with inheritance you are statically bound to the class hierarchy. You seem to imply that delegation and inheritance can be freely substituted for each other, that it's just an arbitrary choice by the developer.
Nothing could be further from the truth.
They are very different and come with different trade-offs.
Granted, delegation has a few good properties (less coupling) but the price is that you lose type substitution. And sometimes, you really need your subclasses to obey the LSP. I agree with Mike: while deep hierarchies should be avoided, they are sometimes unavoidable and a better choice than any alternative. Even if this alternative is delegation.You can have a lot more fun with a Wallet that has-a Currency than a DollarWallet that is-a Wallet. Perfect illustration of what I was saying earlier: if I have a method
stuffWallet(Wallet w)
I can invoke
stuffWallet(new MikeWallet())
but not
stuffWallet(new AslakWallet())
And you do want to stuff this wallet, don't you?
-- Cedric
|
|
Message #118721
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
OO Without Inheritance
No, what's unfair is making dismissive statements like 'all inheritance is bad design' in order to justify a particular technical advocacy position And who did this?
I think the word used was "usually"... as in "they're usually a code smell"...
-Nick
|
|
Message #118722
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
OO Without Inheritance
but the price is that you lose type substitution Unless you use interfaces. There is not much point to composition if you dont have type substitution... (as the winforms users are finding out)
-Nick
|
|
Message #118735
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
CDI and TDD
I agree, one of the main benefits of CDI is how well it aligns with TDD. With a test-first design, you typically end up passing hard-to test dependencies to the constructor, via interfaces. CDI is the most naturall way to inject the dependent components in run-time. If you start with a TDD design for a component, and then figured out how to write a component container to inject the dependencies, you'd end up with a simple CDI injection based container.
Of coures not all components are written test first in the real world, and we need to integrate with stuff we can't control. So setter injection is also important to support legacy components, and for interesting esoteric cases where CDI is not so pratical (deeply nested inheritance hierachies, reams of parameters, etc.). But if you really design your components TDD style, I think you'll find that CDI is the most elegant and least invasive way to go *most* (not all) of the time.
|
|
Message #118744
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
"constructor-based dependency injection"!?!?!?
What's all the fuss about? This is basic OO coding. It's not a design pattern. It's not something new. For as long as I've been coding in OO languages it's been considered good coding practice to provide constructors that create well-formed instances of your objects. You pass in whatever parameters are needed to create well-formed instances.
At the same time it's always been considered to be bad coding practice to create zero argument constructors and set all the attributes with individual "setter" methods.
People argue in the abstract that it's too difficult to create "proper" constructors in practice - that you end up with too many variations of sets of parameters for different constructors. In practice, I've never found this to be the case.
And in today's world of IDE's with built in Refactorings, is it really a big deal to add an additional parameter to a constructor if your object changes over time?
|
|
Message #118752
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
XML
What about passing some XML to the CSTR?
It's flexible, but doesn't have static type checking.
|
|
Message #118780
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
"constructor-based dependency injection"!?!?!?
For as long as I've been coding in OO languages it's been considered good coding practice to provide constructors that create well-formed instances of your objects. You pass in whatever parameters are needed to create well-formed instances.At the same time it's always been considered to be bad coding practice to create zero argument constructors and set all the attributes with individual "setter" methods.People argue in the abstract that it's too difficult to create "proper" constructors in practice - that you end up with too many variations of sets of parameters for different constructors. In practice, I've never found this to be the case.And in today's world of IDE's with built in Refactorings, is it really a big deal to add an additional parameter to a constructor if your object changes over time? Couldn't agree more with that. What is new is how IoC containers like Pico and Spring provide extra support for this coding style. Instead of instantiating dependent objects directly in your code, the container instantiates them for you, providing the correct implementation of an interface based on a configuration. This allows you to separate configuration from implementation. Here's a good intro article:
http://www.martinfowler.com/articles/injection.html
You may or may not like it, but it is something new.
|
|
Message #118784
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Oh no "dependency injection"....
The terms "dependency injection" or "inversion of control" are probably two of the most bloated terms I came across in my entire carreer (and it's been going on for some time). The dependencies in "dependency injection" are actually in the classes more often than not. There is no "dependency" injected. You either depend on an interface in your "bean" or "business object" or on a class. That is it. By configuring a particular object No dependency is injected. What is injected (if anything) is a reference.
Much the same with "inversion of control". How about calling it "configuration" as this exposes what is done. But then nothing would be inversed, would it, because "configuration" has been done on the outside for ages. And the actual business processes are not "inversed" in any way. They are still pretty much linearly driven.
Now really.....
|
|
Message #118788
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Constructor Based Injection and Design
The problem that I have with Constructor Based Injection is the concept of well formed objects. When the object is coded and designed with a constructor based injection you have a already determined the business rules for the object. These rules are applied to the constructor and are immutable.
Now this object is directly tied to a certain set of business rules to determine well-formedness and cannot be reused cleanly for disparate solutions. Even some of the most basic rules you can come up with for a bean validation may not apply to all solutions.
I prefer to apply a combination of constuctor based and setter based injection. By that, I tend to have a number of limited parameter constuctors available as well as some business rules based constuctors using constructor based injection. Therefore I can apply to object to multiple solutions.
The devil in these details occurs when having a team member that does not fully understand the code base. Then, a number of coding errors can occur because of developers not looking fully into the compositon of an object that they are using. Assuptions are made that the object is made well formed because the developer hasn't read the Javadoc or other supporting documentation.
I have applied this philosophy to JavaBeans, POJOs, and complex objects such as JNDI, SQL, DAO, JMS factories. It provides the greatest flexabilty and reuse, but requires displine.
|
|
Message #118992
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Immutable objects are possible with setters
Using a framework like spring, you can define and object with setters and an interface with no setters. Simply use the interface and you have an immutable object with setter injection
|
|
Message #119008
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Immutable objects are possible with setters
To be precise: Immutable interfaces to a mutable object are possible. The object itself is still mutable. Someone can still do:
MyInterface i = new MyImpl(); i.someMethod(); // whoops - forgot to initialize properly
|
|
Message #119059
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Oh no "dependency injection"....
Either you are missing the point, or you are trying to be difficult :-)
When you read "dependency injection", read "dependency instance injection". When you read "inversion of control", read "inversion of control of instantiation"
The whole point is that the a component does not instantiate its dependancies. Therefore, it doesnt know what concrete types these are - nor where they came from - nor what their dependancies are.
Now, for some people, this is Nothing New TM. (Most people doing proper unit testing would have discovered this by themselves - maybe not even realising it)
However, for many people this is a big shift. They are used to their component instantiating its dependancies (in fact, knowing what to instantiate is deemed part of the encapsulation)
In the end, though, its a very, very useful pattern.
So.... yes... really!
|
|
Message #119074
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Oh no "dependency injection"....
(Most people doing proper unit testing would have discovered this by themselves - maybe not even realising it)However, for many people this is a big shift. They are used to their component instantiating its dependancies (in fact, knowing what to instantiate is deemed part of the encapsulation)In the end, though, its a very, very useful pattern.So.... yes... really! I think most people do what I did for several years, instead of writing true unit tests which test methods in isolation, most people write "integration tests" which test objects and their dependencies. I see this all the time and I recognize it now that I've learned how to write Mock Objects (using jMock). A quick example: A coworker wanted to test his wrapper for the Apache commons HttpClient. So he coded up unit tests hitting yahoo.com and other websites. I was running the unit tests on my notebook on the train and they failed (obviously). His "unit tests" were in fact testing not only his "unit" but also HttpClient. This is a really simple example but it's very common. Another example is testing database access code.
Michael Mattox
|
|
Message #119127
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Oh no "dependency injection"....
Either you are missing the point, or you are trying to be difficult :-)
When you read "dependency injection", read "dependency instance injection". When you read "inversion of control", read "inversion of control of instantiation" Well, to be precise, "inversion of control" refers to a characteristic common to frameworks. In the procedural paradigm, you had a set of function libraries, and when you write your system, generally you are responsible to design and code the flow of processing ('control'). Frameworks put it upside down, taking care of the main flow of processing and leaving the responsibility of the low-level (or business-specific) coding to you ('inversion of control'). This is often refered as 'the hollywood principle', or 'don't call us, we call you', because it's not your code that calls library functions, but the framework that calls YOUR functions/objects.
This principle allows the configuration/customization of the framework (general) to fit our needs (specific).
So, Karl isn't completely wrong about the configuration stuff, but the way this configuration is done is completely different. Pure configuration assumes that all code needed is already there, and you just need to set some flags to change the portion of code used. 'Inversion of Control' is a principle that allows customization of behavior by coding replaceable modules.
You may say 'But I've done callbacks for ages as well'. OK, callbacks are made, but it is the 'concrete' term (implementation). 'Inversion of Control' would be the 'abstract' term (concept).
Then, Nick, you are almost correct, just that those terms don't refer only to object instantiation, but to flow control (processing) as well. (or maybe I'm trying to be difficult?) =)
|
|
Message #120441
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Re: Constructor Syntax
Try:public TaxBasis( String customerId )aandpublic TaxBasis( String companyId ) Actually this won't compile. You can't have two constructors with the same signature. The type or number of parameters has to be different. Perhaps this was a typo? I believe that was his point.
|
|
Message #121943
Post reply
Post reply
Post reply
Go to top
Go to top
Go to top
|
 |
Cyclic dependencies with constructor-based dependency injection?
Imagine you have two components which are dependend to each other (e.g. think about a GUI and a controller component which are interacting together). How will you do this with Constructor Injection? Pico will give you a CyclicDependencyException...
|
|
 |
New content on TheServerSide.comNew content on TheServerSide.comNew content on TheServerSide.com |
 |
 |
Reza Rahman explores the features of the proposed JSR 299, Contexts and Dependency Injection for Java EE (CDI). When approved, it promises to be a key feature of Java EE 6.
(November 2, Article)
SAML is an XML-based standard for exchanging authentication and authorization data between security domains. The single most important problem that SAML was created to solve is the Web browser Single Sign-On problem. Many organizations are debating whether to stay with version 1.1 or move to 2.0. This article makes observations about both options.
(September 28, Article)
Joe Ottinger takes a look at how people learn, and applies it to the practice of programming. He notes that understanding how people learn is an essential part of working in a programming team.
(September 22, Article)
Stephen Maryka gave us an article about the Asynchronous Web and posed a number of questions that get examined like an approach to delivering Asynchronous Web capabilities through extensions to existing Java EE technologies.
(July 14, Article)
JavaServer Faces Flex goal is to provide users capability in creating standard Flex components, part of flexSDK which is open sourced through MPL license, as normal JSF components. This article by Ji Hoon Kim will provide an overview of creating a simple multilingual JSF page consisting of JSF Flex tags.
(June 29, Article)
In this session Jeff explores the key characteristics of successful SOA projects. He covers some of the patterns, and anti-patterns, tool sets, and strategies that he himself learned the hard way. Last, he provides a strategy and blueprint for achieving a high likelihood of success in your SOA project.
(June 23, Tech Talk)
Ari Zilka, CTO of Terracotta, Inc., talks about the new features in Terracotta 3.1, announced during JavaOne and available now.
(June 15, Tech Talk)
In this Tech Talk, Josh Long explores an integration challenge using Spring Integration and walks through the implementation, employing and expanding on the basic patterns of Enterprise Application Integration to tie together components into a function integration solution, and then demonstrates how Spring Integration helps address the integration requirements.
(June 15, Tech Talk)
In this Tech Talk, David Geary teaches you: The basics of Google Web Toolkit; How to implement Ajax-enabled applications in Java; Internationalization; Hooking into the browser history mechanism; Remote procedure calls.
(June 4, Tech Talk)
Jon Kern discusses the best architecture/technical solutions and ensure that they are repeated by all developers. By tackling the architecture up-front in a serial manner, subsequent parallel development will be much more manageable and predictable.
(May 28, Tech Talk)
This keynote describes the frustrations of modern knowledge workers in their quest to actually get some work done, and solutions for how to guard yourself against all those distractions. Neal Ford talks about environments, coding, acceleration, automation, and avoiding repetition as ways to defeat the misguided attempts to sap your ability to produce good work.
(May 26, Tech Talk)
Gil demonstrates how new, aggressive uses of already abundant compute capacity by common applications offer competitive value for application designers.
(May 21, Tech Talk)
Chris Keene introduces WaveMaker as a new way to automate the ability to generate Hibernate classes in order to more quickly bring OR mapping into an application.
(May 19, Article)
In this session Nati Shalom demonstrates how to take a standard Java EE web application and scale it out or down dynamically without changes to the application code. Seeing as most web applications are over-provisioned to meet infrequent peak loads, this is a dramatic change because it enables growing your application as needed, when needed, without paying for unutilized resources.
(May 19, Tech Talk)
Download the entire book of Jakarta-Struts Live and learn about Struts MVC, Tiles, the Validator, DynaActionForms, plug-ins, internationalization, and more.
(Book PDF Download)
The Application Server Matrix is a detailed listing of J2EE vendors and their application server products, with information on latest version numbers, J2EE spec support and licensing, pricing, platform support, and links to product downloads and reviews.
(Application Server Comparison Matrix)
|
|