Hello! I have a class that takes many arguments to create. It’s a sort of an audio processor that needs a sample rate, sample resolution, number of channels etc. Most of the parameters have sane defaults. And most of them should be only settable in the initializer (constructor), because it makes no sense to change them afterwards. I do not want to create a gargantuan initializer with all the parameters because (1) it would be huge and essentially it would only copy the passed values, doing no real work, and (2) the user would have to specify values for all the parameters. What’s a good way to solve this?
I’ve tried writing getters and setters for the params. This means that I could not create the “real” audio processing unit in the constructor, since the parameter values are not known then. I had to introduce a new method (say prepareForWork
) so that the users can do something like:
AudioProcessor *box = [[AudioProcessor alloc] init];
[box setSampleRate:…];
[box setNumberOfChannels:…];
[box prepareForWork];
[box doSomeProcessing];
This is nice because it does not require an unwieldy constructor. Also the defaults are set in the initializer which means that I can take a fresh AudioProcessor
instance and it could still do some work. The flip side is that (1) there is an extra method that has to be called before the instance can do any real work and (2) the class should refuse to change any of the parameters after prepareForWork
was called. Guarding both these invariants would take some boilerplate code that I don’t like.
I thought I could create a special “preset” class that would look like this:
@interface SoundConfig : NSObject {
NSUInteger numberOfChannels;
NSUInteger sampleResolution;
float sampleRate;
}
And then require an instance of this class in the AudioProcessor
initializer:
@interface AudioProcessor : NSObject {…}
- (id) initWithConfig: (SoundConfig*) config;
Default values would be set in the SoundConfig
initializer, the AudioProcessor
constructor would be simple and there would be no invariants to keep watching by hand.
Another approach I thought of was a kind of AudioProcessorBuilder
class. You would create an instance of that, set the audio params through accessors and then finally it would build an AudioProcessor
instance for you, setting all the properties through a non-public setters so that you could not change them later (and break the invariant).
Now that I write this I favour the SoundConfig
approach. How do you solve this, is there a better approach?