Let's say we want to encapsulate a collection of read-only configuration parameters into a class (so, we want immutability). There are numerous parameters in the configuration, perhaps dozens - so we don't want to provide some ugly multi-parameter constructor or factory method. In fact, we want to provide clients with the convenience of static getters, so we know this will be a utility class (i.e. no instances needed or desired). While we could initialize a list of static fields with their configuration values to facilitate this, we would rather factor these value out into some external file.
We'd like to use Spring - but Spring works on instances, and we don't have a constructor for Spring to use, nor do we want or need an instance anyway, nor do we want to provide setters on this class (since we would like to stay immutable). So, how to use Spring?
One solution is to use a variation on the Builder pattern - the recipe goes like this:
- create the utilty class with static fields for each configuration parameter
- give it a private constructor
- provide static getters for each parameter
- add a static inner class with the same fields, although these will be instance fields (not static)
- this inner class also has a private constructor
- provide setters for each field - although here we deviate from the standard Builder pattern: these are true setters, returning void
- the utility class now provides a static "init" method that accepts an instance of the inner class as an argument - and this behaves just like the regular Builder pattern, where the top-level class initializes its fields from the correspond fields in the argument object
- the inner class provides its own "init" method which calls the utility class init method with itself
Spring wires all of this together like this:
<bean id="builder-variant" class="com.mybiz.MyUtilityClass$MyInnerClass"
init-method="initUtilityClass">
<property name="foo" value="bar"/>
<property name="bar" value="foo"/>
</bean>
Using this, Spring will create an instance of the inner class, setting its properties as given, and then call the inner class' initializer. As mentioned in the above recipe, that initializer will then call the utility class' initializer with itself as the argument. That facilitates initializing the utility class properties, and we're done.
This was very helpful today. Worked like a charm.
ReplyDeleteWonderful!! This is absolutely brilliant.
ReplyDeleteI'll definitely use this. Thanks.
ReplyDelete