On Sep 27, 2007, at 9:58 PM, Alejandro MartÃnez wrote:
In which case do you create specialized class message for instantiating an object?
I think two factors are fundamental:
- You want to enforce correcteness of your objects by making sure
they are complete, so you "minimize" #new and provide specialized messages for creation. 2) You do not want to enforce anything until real usage experience shows you which messages you must "promote" to the class side.
My personal view is 2) would be more humble at first, but since this is a question so dependent of the domain you're implementing and your knowledge about it, I'd like to know which patterns or approaches have you seen or taken through the years.
Hi Alejandro,
In my experience, the thing to be thinking about is clarity. Will creating a specialized instance-creation method make your code easier to understand? If so, do it.
Take the class Semaphore as an example. #forMutualExclusion is a great method. The implementation is pretty trivial, you could replace all the senders with "Semaphore new signal" without complicating the code much. But you'd have a huge loss in terms of clarity. With "Semaphore forMutualExclusion" it's obvious what you're doing, so much so that you don't even have to remember the details of how to use semaphores as mutexes. #forMutualExclusion and #critical: are all you need.
Don't worry about 1). You can't "enforce" anything in Smalltalk anyway, and if you could it would just make life difficult for the next guy who has to deal with the code - and chances are good that guy is you. Instead, try to make life easier for the users of the code.
Don't worry about 2) either. If experience shows you a better way to initialize objects of a particular class, use it. You can have more than one instance-creation method if you want, or update all the senders of the old method to use the new one. Don't worry at all about doing one thing and then changing your mind later.
One final thought. I find that I like to organize an object's state according to its life-cycle. If there are certain variables that are set when an object is created and are never changed over its lifetime, I create a specific constructor for those variables, and a single initializer method something like #setFoo:bar:baz: on the instance side. I might have getters for those ivars, but almost never have setters. This is the kind of that often forms the "identity" of the object, so having specialized constructor and initializer methods helps make that clear.
On the other hand, I usually don't include volatile state in specialized constructors. Instead, I create both getters and setters, possibly with lazy initialization, and leave it to the users to supply that volatile state. Combining these patterns might yield something like this:
(House atAddress: '123 Main St.') color: Color blue; bedrooms: 3; yourself
The address of the house won't change, but it might get a new coat of paint, or an addition. These aren't hard and fast rules, of course, but habits that I seem to follow.
Colin