Testing Blog

Constructor Injection vs. Setter Injection

Thursday, February 19, 2009
Share on Twitter Share on Facebook
Google
Labels: Misko Hevery

17 comments :

  1. UnknownFebruary 19, 2009 at 10:50:00 AM PST

    A big pro for constructor injection is the possibility to build immutable objects out of it.

    ReplyDelete
    Replies
      Reply
  2. seregaFebruary 19, 2009 at 1:58:00 PM PST

    That's all sounds very good, immutability is good. But, I don't agree that code is easier to read with constructor injection.
    When there are many depended objects, and especially, if they are of the same class it becomes hard to read and to write such code. In your example you have
    Database db = new Database("username", "password", "jdbc:....");
    It is error prone to construct such object, because all arguments are Strings, and they must be passed in the right order. Compiler can't help here.
    With setters it is clear, and there is no ambiguity.

    But, in general, I like immutable objects. Perhaps Joshua Bloch Builder pattern can help here.
    Database database = new Database.Builder()
    .url("url")
    .user("user")
    .password("pass").build();

    ReplyDelete
    Replies
      Reply
  3. Adam TyborFebruary 19, 2009 at 2:47:00 PM PST

    I tend to always use constructor injection. I will only use setter injection for optional dependencies.

    For example if I want to use a logger when I am not using aspects, instead of requiring an ILogger in the constructor I will have a setter for ILogger.

    In my constructor I instantiate the logger with Logger.NullLogger and my container can wire up the real logger implementation at runtime.

    Using constructor injection makes it very explicit that certain dependencies are "required" for the object to function.

    You are correct that with setter injection you loose focus of this, but using setter injection for optional dependencies creates a little less noise too.

    ReplyDelete
    Replies
      Reply
  4. Pierre-Antoine GrégoireFebruary 20, 2009 at 4:15:00 AM PST

    Using Constructor injection for mandatory parameters is really the best scenario.
    In order to remove the problem mentioned by serega, a nice practice is to improve your domain by adding additional objects like "Credentials", "DataBaseConnectionInfo" and so on...
    These ones may use getters/setters or even better a builder pattern.
    You finally have a richer
    new Database(credentials,databaseInfo);
    constructor with no possible misunderstanding on the order of parameters.

    Though I'd like to mention that immutable are really a nice-to-have, but are completely incompatible with the (sadly) widely used javabeans spec... This is one of the reasons why Spring used the setters and no-param constructor, in order to benefit from this spec.

    Be my guest and try to expose an immutable object with JaxWS ;)...

    ReplyDelete
    Replies
      Reply
  5. Adam OlsenFebruary 20, 2009 at 2:31:00 PM PST

    serega, that can be solved by using keyword arguments, if the language supports them.

    db = Database(url="url", user="user", password="pass")

    ReplyDelete
    Replies
      Reply
  6. Andrew EisenbergFebruary 20, 2009 at 3:50:00 PM PST

    You forgot to mention a serious advantage of setter injection. It is the ability to ignore defaults.

    Using constructor injection, you either get an explosion of constructors (where each constructor takes a certain subset of all arguments), or you are forced to provide values for attributes that where the defaults are sufficient.

    If you are using a DI framework (like Spring, maybe like Guice, but never used it yet), you are shielded from object construction anyway, so it is largely irrelevant which form you use.

    If you are not using a DI framework, then I, too, am partial to Josh Bloch's builder.

    ReplyDelete
    Replies
      Reply
  7. martinFebruary 21, 2009 at 3:01:00 PM PST

    I am totally pro constructor injection, as it enforces consistent objects, and prevents null pointers (forgot to set an object).

    However, how do we keep our constructors lightweight? If we do constructor injection, won't we be tempted to violate http://misko.hevery.com/code-reviewers-guide/ rule #1?

    ReplyDelete
    Replies
      Reply
  8. Adam OlsenFebruary 22, 2009 at 2:39:00 AM PST

    @Andrew: keyword arguments let you skip default too. You could have 5 arguments and only give the last one.

    Of course if the language you're using doesn't support them then setter injection might be the least ugly option.

    ReplyDelete
    Replies
      Reply
  9. Eric JainFebruary 22, 2009 at 11:16:00 AM PST

    I'll second the recommendation to use builders as a way to keep the setup code readable (especially in languages such as Java where you don't have default or named parameters) and have immutable objects without exposing a growing number of constructors.

    Spring btw supports circular dependencies even when using constructor injection!

    ReplyDelete
    Replies
      Reply
  10. MikeFebruary 23, 2009 at 6:22:00 AM PST

    I would be very curious to hear the author's thoughts about dependency injection with OSGi. I don't get the impression that OSGi is used within Google. If not, I was wondering if the author could comment on its relative merits for these problems.

    ReplyDelete
    Replies
      Reply
  11. Philipp MeierFebruary 25, 2009 at 5:44:00 AM PST

    Constructor Injection has another plus: assuming the constructed component implements an interface, you can refer to the freshly built object by the interface and "forget" the implementation type after construction. With Setter Injection to make use of the setters you must assign the instance to a reference of the actual implementation type.


    e.g.

    CreditCardProcessor processor = new CreditCardProcessorImpl(database, ...)

    vs.

    CreditCardProcessorImpl processor = new CreditCardProcessorImpl();
    processor.setDatabse(...);

    ReplyDelete
    Replies
      Reply
  12. UnknownMarch 5, 2009 at 1:58:00 PM PST

    If you're worried about mixing up the order of string parameters, one option is to turn some of them into a parameter object, e.g.:

    DbAuth auth = new DbAuth("user", "pass");
    String url = "jdbc:...";
    new Database(auth, url);

    ReplyDelete
    Replies
      Reply
  13. Steve FreemanMarch 14, 2009 at 6:35:00 AM PDT

    @serega If you have that many dependencies, then it's most likely that either your class is too large or that some of your dependencies should be packaged up into a higher level structure.

    ReplyDelete
    Replies
      Reply
  14. Steve FreemanMarch 14, 2009 at 6:36:00 AM PDT

    If I have a range of configurations, one pattern I like is to keep DI in the constructor very simple (just set the final fields) and use factory methods to create the different versions. Not least because I can give them descriptive names, rather than just different constructors.

    ReplyDelete
    Replies
      Reply
  15. Luke MeyersMarch 27, 2009 at 10:59:00 AM PDT

    The best argument in favor of "constructor injection" that I don't see here yet is that it's vastly preferable to construct complete objects. This is an invaluable invariant, and the constructor is the place to establish that invariant. I can't exaggerate how much easier life is if you don't have to ask yourself whether that object is really ready to be used, or if it's in some weird half-assembled state with unpredictable, nonsensical behavior.

    As for the issue that was mentioned about constructor arguments that are hard to tell apart because they're all strings (or ints, or even worse bools), fair point. One solution is to be sensitive in your design and regard excessive numbers of parameters as a code smell.

    Another approach that can be taken sometimes is to create trivial wrapper types -- if e.g. an accountId is represented as a string, that doesn't mean it should be passed around as one; that just tempts us to accidentally try and make it interoperate or interchange with other strings that are *not* accountIds. I wouldn't do this universally, but it can be worth it for commonly-used entity types that are passed around a lot.

    ReplyDelete
    Replies
      Reply
  16. seregaMarch 27, 2009 at 12:38:00 PM PDT

    I just want to point out that I do prefer "constructor injection" and always try to use it in my code. There are many valid points mentioned the post and in the comments. I just want to add that immutable objects make working with concurrent code (which I often do) a lot easier, because you don't need to do any synchronization. When you publish an object with all final fields JVM guarantees that those fields will be initialized.
    Back to readability.
    Adam Olsen:
    Java does not support defaults in the arguments.
    zepaq and Luke:
    I agree that introducing rich wrappers can solve the problem of ambiguity and readability, but you are not going to do that for each String, int and bool in your code. Often you work with existing API that use primitives, so you will have to wrap that API to make it "richer". Unless you are a solo developer, that can make the problem worse, because the readers of you code will have to learn your new "rich" API.

    ReplyDelete
    Replies
      Reply
  17. UnknownApril 10, 2014 at 8:21:00 AM PDT

    nice post

    ReplyDelete
    Replies
      Reply
Add comment
Load more...

The comments you read and contribute here belong only to the person who posted them. We reserve the right to remove off-topic comments.

  

Labels


  • TotT 104
  • GTAC 61
  • James Whittaker 42
  • Misko Hevery 32
  • Code Health 31
  • Anthony Vallone 27
  • Patrick Copeland 23
  • Jobs 18
  • Andrew Trenk 13
  • C++ 11
  • Patrik Höglund 8
  • JavaScript 7
  • Allen Hutchison 6
  • George Pirocanac 6
  • Zhanyong Wan 6
  • Harry Robinson 5
  • Java 5
  • Julian Harty 5
  • Adam Bender 4
  • Alberto Savoia 4
  • Ben Yu 4
  • Erik Kuefler 4
  • Philip Zembrod 4
  • Shyam Seshadri 4
  • Chrome 3
  • Dillon Bly 3
  • John Thomas 3
  • Lesley Katzen 3
  • Marc Kaplan 3
  • Markus Clermont 3
  • Max Kanat-Alexander 3
  • Sonal Shah 3
  • APIs 2
  • Abhishek Arya 2
  • Alan Myrvold 2
  • Alek Icev 2
  • Android 2
  • April Fools 2
  • Chaitali Narla 2
  • Chris Lewis 2
  • Chrome OS 2
  • Diego Salas 2
  • Dori Reuveni 2
  • Jason Arbon 2
  • Jochen Wuttke 2
  • Kostya Serebryany 2
  • Marc Eaddy 2
  • Marko Ivanković 2
  • Mobile 2
  • Oliver Chang 2
  • Simon Stewart 2
  • Stefan Kennedy 2
  • Test Flakiness 2
  • Titus Winters 2
  • Tony Voellm 2
  • WebRTC 2
  • Yiming Sun 2
  • Yvette Nameth 2
  • Zuri Kemp 2
  • Aaron Jacobs 1
  • Adam Porter 1
  • Adam Raider 1
  • Adel Saoud 1
  • Alan Faulkner 1
  • Alex Eagle 1
  • Amy Fu 1
  • Anantha Keesara 1
  • Antoine Picard 1
  • App Engine 1
  • Ari Shamash 1
  • Arif Sukoco 1
  • Benjamin Pick 1
  • Bob Nystrom 1
  • Bruce Leban 1
  • Carlos Arguelles 1
  • Carlos Israel Ortiz García 1
  • Cathal Weakliam 1
  • Christopher Semturs 1
  • Clay Murphy 1
  • Dagang Wei 1
  • Dan Maksimovich 1
  • Dan Shi 1
  • Dan Willemsen 1
  • Dave Chen 1
  • Dave Gladfelter 1
  • David Bendory 1
  • David Mandelberg 1
  • Derek Snyder 1
  • Diego Cavalcanti 1
  • Dmitry Vyukov 1
  • Eduardo Bravo Ortiz 1
  • Ekaterina Kamenskaya 1
  • Elliott Karpilovsky 1
  • Elliotte Rusty Harold 1
  • Espresso 1
  • Felipe Sodré 1
  • Francois Aube 1
  • Gene Volovich 1
  • Google+ 1
  • Goran Petrovic 1
  • Goranka Bjedov 1
  • Hank Duan 1
  • Havard Rast Blok 1
  • Hongfei Ding 1
  • Jason Elbaum 1
  • Jason Huggins 1
  • Jay Han 1
  • Jeff Hoy 1
  • Jeff Listfield 1
  • Jessica Tomechak 1
  • Jim Reardon 1
  • Joe Allan Muharsky 1
  • Joel Hynoski 1
  • John Micco 1
  • John Penix 1
  • Jonathan Rockway 1
  • Jonathan Velasquez 1
  • Josh Armour 1
  • Julie Ralph 1
  • Kai Kent 1
  • Kanu Tewary 1
  • Karin Lundberg 1
  • Kaue Silveira 1
  • Kevin Bourrillion 1
  • Kevin Graney 1
  • Kirkland 1
  • Kurt Alfred Kluever 1
  • Manjusha Parvathaneni 1
  • Marek Kiszkis 1
  • Marius Latinis 1
  • Mark Ivey 1
  • Mark Manley 1
  • Mark Striebeck 1
  • Matt Lowrie 1
  • Meredith Whittaker 1
  • Michael Bachman 1
  • Michael Klepikov 1
  • Mike Aizatsky 1
  • Mike Wacker 1
  • Mona El Mahdy 1
  • Noel Yap 1
  • Palak Bansal 1
  • Patricia Legaspi 1
  • Per Jacobsson 1
  • Peter Arrenbrecht 1
  • Peter Spragins 1
  • Phil Norman 1
  • Phil Rollet 1
  • Pooja Gupta 1
  • Project Showcase 1
  • Radoslav Vasilev 1
  • Rajat Dewan 1
  • Rajat Jain 1
  • Rich Martin 1
  • Richard Bustamante 1
  • Roshan Sembacuttiaratchy 1
  • Ruslan Khamitov 1
  • Sam Lee 1
  • Sean Jordan 1
  • Sebastian Dörner 1
  • Sharon Zhou 1
  • Shiva Garg 1
  • Siddartha Janga 1
  • Simran Basi 1
  • Stan Chan 1
  • Stephen Ng 1
  • Tejas Shah 1
  • Test Analytics 1
  • Test Engineer 1
  • Tim Lyakhovetskiy 1
  • Tom O'Neill 1
  • Vojta Jína 1
  • automation 1
  • dead code 1
  • iOS 1
  • mutation testing 1


Archive


  • ►  2025 (1)
    • ►  Jan (1)
  • ►  2024 (13)
    • ►  Dec (1)
    • ►  Oct (1)
    • ►  Sep (1)
    • ►  Aug (1)
    • ►  Jul (1)
    • ►  May (3)
    • ►  Apr (3)
    • ►  Mar (1)
    • ►  Feb (1)
  • ►  2023 (14)
    • ►  Dec (2)
    • ►  Nov (2)
    • ►  Oct (5)
    • ►  Sep (3)
    • ►  Aug (1)
    • ►  Apr (1)
  • ►  2022 (2)
    • ►  Feb (2)
  • ►  2021 (3)
    • ►  Jun (1)
    • ►  Apr (1)
    • ►  Mar (1)
  • ►  2020 (8)
    • ►  Dec (2)
    • ►  Nov (1)
    • ►  Oct (1)
    • ►  Aug (2)
    • ►  Jul (1)
    • ►  May (1)
  • ►  2019 (4)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Jul (1)
    • ►  Jan (1)
  • ►  2018 (7)
    • ►  Nov (1)
    • ►  Sep (1)
    • ►  Jul (1)
    • ►  Jun (2)
    • ►  May (1)
    • ►  Feb (1)
  • ►  2017 (17)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Oct (1)
    • ►  Sep (1)
    • ►  Aug (1)
    • ►  Jul (2)
    • ►  Jun (2)
    • ►  May (3)
    • ►  Apr (2)
    • ►  Feb (1)
    • ►  Jan (2)
  • ►  2016 (15)
    • ►  Dec (1)
    • ►  Nov (2)
    • ►  Oct (1)
    • ►  Sep (2)
    • ►  Aug (1)
    • ►  Jun (2)
    • ►  May (3)
    • ►  Apr (1)
    • ►  Mar (1)
    • ►  Feb (1)
  • ►  2015 (14)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Oct (2)
    • ►  Aug (1)
    • ►  Jun (1)
    • ►  May (2)
    • ►  Apr (2)
    • ►  Mar (1)
    • ►  Feb (1)
    • ►  Jan (2)
  • ►  2014 (24)
    • ►  Dec (2)
    • ►  Nov (1)
    • ►  Oct (2)
    • ►  Sep (2)
    • ►  Aug (2)
    • ►  Jul (3)
    • ►  Jun (3)
    • ►  May (2)
    • ►  Apr (2)
    • ►  Mar (2)
    • ►  Feb (1)
    • ►  Jan (2)
  • ►  2013 (16)
    • ►  Dec (1)
    • ►  Nov (1)
    • ►  Oct (1)
    • ►  Aug (2)
    • ►  Jul (1)
    • ►  Jun (2)
    • ►  May (2)
    • ►  Apr (2)
    • ►  Mar (2)
    • ►  Jan (2)
  • ►  2012 (11)
    • ►  Dec (1)
    • ►  Nov (2)
    • ►  Oct (3)
    • ►  Sep (1)
    • ►  Aug (4)
  • ►  2011 (39)
    • ►  Nov (2)
    • ►  Oct (5)
    • ►  Sep (2)
    • ►  Aug (4)
    • ►  Jul (2)
    • ►  Jun (5)
    • ►  May (4)
    • ►  Apr (3)
    • ►  Mar (4)
    • ►  Feb (5)
    • ►  Jan (3)
  • ►  2010 (37)
    • ►  Dec (3)
    • ►  Nov (3)
    • ►  Oct (4)
    • ►  Sep (8)
    • ►  Aug (3)
    • ►  Jul (3)
    • ►  Jun (2)
    • ►  May (2)
    • ►  Apr (3)
    • ►  Mar (3)
    • ►  Feb (2)
    • ►  Jan (1)
  • ▼  2009 (54)
    • ►  Dec (3)
    • ►  Nov (2)
    • ►  Oct (3)
    • ►  Sep (5)
    • ►  Aug (4)
    • ►  Jul (15)
    • ►  Jun (8)
    • ►  May (3)
    • ►  Apr (2)
    • ▼  Feb (5)
      • Fast exploratory tests with IFrames
      • TotT: Partial Mocks using Forwarding Objects
      • Constructor Injection vs. Setter Injection
      • To Assert or Not To Assert
      • TotT: Be an MVP of GUI Testing
    • ►  Jan (4)
  • ►  2008 (75)
    • ►  Dec (6)
    • ►  Nov (8)
    • ►  Oct (9)
    • ►  Sep (8)
    • ►  Aug (9)
    • ►  Jul (9)
    • ►  Jun (6)
    • ►  May (6)
    • ►  Apr (4)
    • ►  Mar (4)
    • ►  Feb (4)
    • ►  Jan (2)
  • ►  2007 (41)
    • ►  Oct (6)
    • ►  Sep (5)
    • ►  Aug (3)
    • ►  Jul (2)
    • ►  Jun (2)
    • ►  May (2)
    • ►  Apr (7)
    • ►  Mar (5)
    • ►  Feb (5)
    • ►  Jan (4)

Feed

  • Google
  • Privacy
  • Terms