In grading student homework, I found myself enunciating the following principle:
If it's not a bean property, if at the very least you don't have a get method for it, it's probably not something you want to pass in as an argument to the constructor. And definitely not to a public constructor.
As a rule of thumb, this seems reasonable. I can think of several exceptions (passing in things which involve system resources, like sockets or database connections) and, all in all, it seems a bit too peremptory.
But there's the kernel of a good maxim here. Anyone care to take a shot at refining it (or pointing to the already existing refinement)?
How about "Don't initialize an object into a state that you can't query for later."?
Why? Well, one might pass an object initialized in this way to another object that would have to make a decision based upon the state of that object.
-- NatPryce
Actually I don't agree with this at all! What was I thinking?!?!
An object should not make decisions based on the state of another; it should tell the other object to do something, and that other object can make a decision based on its own state (TellDontAsk).
I think this pattern is a result of too many getters and setters, and too little application of the LawOfDemeter.
-- NatPryce
Can you present an example?
I can ground the discussion a little further, but I don't want to discuss my student's code in detail.
Let's start by saying that bean properties are perfectly reasonable sorts of things to pass in a constructor. That is, if there's a get/set pair on an attribute, then providing a constructor that takes that as an argument is reasonable and frequently good design (constructors often serve as a sort of "mega convenience method" for the most common sequences of set calls).
Now suppose we have an object which is really a wrapper around three distinct strategy objects, each of which can be three things (I have code like this). It's rare that you query an object about the precise strategy it's using (or set it once the object has stabilized). And if you do so, you should probably be asking about characteristics of the strategy, rather than the precise object.
So this latter case is a prime candidate for using a factory to encapsulate the code that decides which strategies to use. I normally go with package level constructors (or even protected ones) that take strategies and a separate factory object that has a nicer API for creation.
If the above makes sense, the question becomes: where's the cutoff point? Is there a "4 legs good, 2 legs bad" sort of statement? When should we switch over from constructors to factories (the GOF book gives reasons to use factories, but not "warning signals in your code").
And the rough draft at the top was a first pass at trying to formulate such a thing.
Avoid Getters and Setters
I'd definitely like an example of this. I dislike getters and setters, so whenever possible, I pass arguments into the constructor and say that from that point on, how an object does what it needs to do is it's own business. Part of this bias comes from the fact that I do not like ModalObject?s: objects where use of part of the protocol is undefined unless the object is in the "right" state. Sure, I do use them, but my bias is always against them. -- MichaelFeathers
I'd like to add my weight in with the "This is wrong" camp. First, Java beans are just designed wrong to begin with (well, that's Java for you). Ask BradCox. They certainly aren't object-oriented. Second, get and set methods aren't required in objects. You only create a get method if it is natural for the object. The constructor is meant to initialize the object in a valid state. There is no connection between that requirement and the naturalness of exposing said state via a get method. The belief that get/set methods are fundamental is just vestigial from the days of structured programming. i.e. "objects are just aggregate types with manipulator functions built in." But this is a bad way to look at objects. -- SunirShah
I agree with the above. The use of get and set methods are an indication of missing functionality within an object. These methods imply that internals of the object need to be externally manipulated. -- WayneMack
My inclination is to agree with the "getters and setters" are wrong camp, and to initialize my object state in constructors. But in practice I seldom find I can work that way. For example, I'd love to make all ValueObjects immutable, but my preferred persistence framework (TOPLink) normally requires instantiation of an object to be a separate activity from loading of its state from the database. -- GrahamJenkins
Some alternatives I use are an Initialize() function that takes an array of parameters, similar to a constructor. Another approach is to embed the SQL call within the object and let the object access the database. -- WayneMack
I mentioned in "DontUseGetAndSet" that excessive use of get and set methods tends to expose the implementation of a class to its clients. This is a bad thing.
I say DontUseGetAndSet, even in a VisualBasic programming environment - where most programmers [mistakenly] think that exposing get and set property methods for all member variables is an OO requirement. -- JeffGrigg
I'm confused. I guess I'm phrasing things badly.
Well, let's take it from another direction. What I'm trying to find is the boundary condition for switching from public constructors to factories. The canonical reason is:
Lots of different places have roughly the same logic, and it has some complexity, in creating the arguments to pass in to the constructor. Refactor to put that logic in one place (and call that place the factory).
What I'm aiming at is a slightly different (but possibly equivalent) reason, based entirely on local code (rather than the global refactoring reason). Sort of the opposite of the LawOfDemeter. Namely, good encapsulation might say that unrelated code (e.g. code from another package) shouldn't ever create an object's internal state and pass it in as part of the constructor.
Which is why I mentioned beans. Because if you can call a get/set pair then there really is no reason why you shouldn't pass the attribute in as part of a constructor.
Now you're saying that you don't like to use getters and setters. Which I find interesting - would you feel differently if you were using Eiffel, with explicitly stated pre and post conditions? How about if you were in Java, where there's a whole set of naming conventions designed to make get/set methods the canonical way to expose attributes?
Anyway ... rephrasing the original question: Are there things you wouldn't pass in to a constructor, or whose presence as constructor arguments would serve as a red flag, to indicate that maybe you should switch over to a Factory-based approach (or do you always rely on the canonical reason, from above)? If so, how would you characterize them?
Thanks. I see where you are coming from now. I just err on the side of simplicity. I would consider ArgumentObject before going to a factory in this situation. The thing about setters is that they imply a "design-time"/"run-time" split in a protocol. Sort of "here are the methods that you use to work with the object, and here are some that you use to change the rug from underneath the object." ... a configuration interface. Configuration interfaces are great if you are designing specifically for reuse, but for me, they are not the first choice for limiting the number of constructor arguments.
The nice thing about ArgumentObject is that your setters are decoupled from the protocol of the object that you pass it to. You can even reduce setters on ArgumentObjects by canning meaningful defaults. As far as getters go, I just find it easier not to put them in until I need them.
I feel strongly about ModalObject?s however. I like to keep as few modes in the interface as possible. In fact, when I use MethodObject, I try to have the constructor compute the value from its arguments if possible, rather than have a separate compute method. It just makes things easier for me to understand. I don't like receiving an object and having to think "Gee, I wonder what mode this thing is in?"
I agree with MichaelFeathers. As long as my experience goes, this is an anti-pattern. What the heck do you think constructors are for? The constructor should create an object in an usable state. What exactly is your justification for it? It doesn't look like you had one till now.
You have to have all the data that make an object function the minute it is created. If that particular data is not easy to gather together to make a single constructor call, then maybe you have to refactor something. Otherwise, it complicates the object as AbstractStateMachine by having bogus states ready-made by the public constructor.
Getting back to the original question of factories instead of constructors...
See EncapsulateConstructorsWithFactoryMethods (and follow the links to pages 5-9 of the PDF paper) for a very good argument for replacing a complex set of constructors with "intention revealing" factory methods. [Paper includes real-world example based on loan types.]
See also LimitParametersForEjbCreates - a similar discussion on limiting constructor arguments.
I think there is a problem with factory methods: if I have a factory to create an A, and then subclass A in B, I cannot reuse the factory to create a B, since the factory includes the call to new. So doesn't this lead to duplicating the body of the factory method? -- DanielBonniot
I'm confused. I guess I'm phrasing things badly.
I don't know. I like to think of a factory as a 'extended constructor', so this never has really bothered me much. I imagine it could cause problems with a sufficiently large number of subclasses, perhaps this would work as work around:
public class FooFactory{ public Foo createFoo(){ Foo foo = createRawFoo(); foo.configure(); return foo; } protected Foo createRawFoo(){ return new Foo(); } }This would allow you to easily subclass the Factory for a given Foo subclass:
public class FooBarFactory extends FooFactory{ protected Foo createRawFoo(){ return new FooBar(); } }What if FooBar needs an (additional) parameter?
public class FooBarFactory extends FooFactory{ public Foo createFooBar(int value) { return createFoo(); //?? } protected Foo createRawFoo(){ return new FooBar(value); // How do I get value here? } }Although at this point it does merely seem like java needs to have a specific 'new' method which can by overridden... oh well, J(ust)MHO. -- WilliamUnderwood
How would that look like?
Possible Rules
My rule of thumb for the use of factory methods versus derived classes is, if the construction is done once, use a factory method; if the construction is done in multiple places, use a derived class. If the same construction is used in multiple places, it is probably a logical type and should be declared as such. If a unique construction is only used once, it is probably just a variation on a single logical type. -- WayneMack
My rule of thumb for what should go into a constructor (or an initialize function if the constructor does not take arguments) is basically every class variable. Immediately after construction/initialization, the object should be fully operational. By putting all of the necessary variables into one function (as opposed to a long list of set attributes), the initialization of the function is documented and it becomes more difficult to incorrectly initialize the object. -- WayneMack
My rule of thumb for what variables should go into a class is that the variable must be used by more than one public method. Do not use set attributes to create parameterless methods. Do not use the class for an easy way to persist a value only used in one place in the class; persist the variable in a separate class and use it when needed. If a variable is used in one public method and lots of private methods, it is usually a good indication that a new embedded class is called for. -- WayneMack
I tend to use separate factory objects (often stateless singletons in java) unless I have a compelling reason not to use them. A lot of people talk about the extra work but I've found the long term payoff is well worth the few extra lines of code. Often a package will have a factory for the objects in that package. It really depends on the use and intent of the objects. -- John Wright
I agree with limiting constructor objects. I have created such objects that initialize 30 or so variables from a no-argument constructor. The object is in a usable state at that point, although probably not in the state it needs to be in. Setting a few of those variables from outside will put it in the right state. I cannot do it from the constructor because the variables to set vary too much. I do not feel like creating a 30 argument constructor.
See also: TooManyParameters