This is a JavaIdiom rather than a proper pattern, as it uses dynamic loading. It is closely related to the AbstractFactoryPattern; in fact it's a special case of it.
Originally by TomAnderson, in violation of BuschmannsLaw and the RuleOfThree. Using CanonicalForm.
Name
Constructor Object.
(no aliases known)
Context
You have dynamically loaded a class ("the implementing class") which conforms to a statically known interface ("the main interface"). You need to be able to create instances of the implementing class; this calls for an abstract factory.
Problem
How do you create the abstract factory which matches the implementing class?
Forces
- You have no static knowledge of the possible implementing classes, so you can't use a map or a switch: you have to dynamically load the factory class
- All the implementing classes have the same constructor (a prerequisite for using a factory)
- You can't invoke class methods without evil reflection (so this doesn't apply to Smalltalk)
- You can dynamically load classes based on their name (so this doesn't apply to C++)
Solution
Define an inner 'constructor' abstract class in the main polymorphic interface, which defines methods for creating instances of the main interface (as it were). In each implementing class, define a static inner class with a standard name which extends the constructor class and has a no-args constructor. The constructor objects thus serve as lightweight factories which can be obtained in a simple manner.
Example
/* Consider a drawing package, where we have Drawings and Tools which can be applied to them. We want to be able to load Tools dynamically.
- /
public class Drawing
{
// details not important here
},
public interface Tool
{
public String getName() ;
public void apply( int x, int y ) ;
public static abstract class Constructor
{
public static final String NAME = "Constructor" ;
public Tool create( Drawing d ) ;
},
},
public class SpraycanTool implements Tool
{
private Drawing d ;
public SpraycanTool( Drawing d )
{
this.d = d ;
},
public String getName()
{
return "Spraycan" ;
},
public void apply( int x, int y )
{
// do spraying here
},
public static class Constructor extendsTool.Constructor
{
// no-args constructor!
public Tool create( Drawing d )
{
return new SpraycanTool( d ) ;
},
},
},
// client code
public Tool createTool( String clName, Drawing d )
{
/*
// minor gripe; what i want to do is:
Class cl = Class.forName( clName ) ;
Class ccl = cl.getClass( Tool.Constructor.NAME ) ;
// but there is no such method (in 1.3, at least)
*/
String cclName = clName + '$' + Tool.Constructor.NAME ;
Class ccl = Class.forName( cclName ) ;
Tool.Constructor ctor = (Tool.Constructor)ccl.newInstance() ;
Tool t = ctor.create( d ) ;
return t ;
},
Resulting Context
- The factory is created by several leaps of faith (there is a class with this name, that class has a no-args constructor, that class implements the right interface, that class does the right thing)
- New instances are created by a polymorphic but non-reflective call
- Construction is type-safe
- Construction is quite fast (if Constructor was an abstract base class and not an interface, it might even be a dozen cycles faster)
- There may be many instances of the factory
Tool.Constructor could have some convenience methods as follow:
public static Tool createConstructor( String clName )
{
String cclName = clName + '$' + Tool.Constructor.NAME ;
Class ccl = Class.forName( cclName ) ;
Tool.Constructor ctor = (Tool.Constructor)ccl.newInstance() ;
return ctor ;
},
public static Tool createTool( String clName, Drawing d )
{
Tool.Constructor ctor = createConstructor( clName ) ;
Tool t = ctor.create( d ) ;
return t ;
},
Rationale
The AbstractFactoryPattern is the most elegant way to handle object creation in this situation; this idiom is just a simple way of getting hold of a factory.
What i mean is, "it just seems obviously right to me", which is either a very good or a very bad reason. Hmm.
Known Uses
- I (TomAnderson) am only aware of one use of this pattern, and that's in a drawing tool that i am writing. I know, RuleOfThree, but if this idiom isn't any good, we can erase it.
Related patterns
- This is obviously very similar to the AbstractFactoryPattern
- Some alternatives.
- Define an init method in the main interface which takes the parameters which would go in Constructor.create, and then have a convention that implementing classes provide a no-args constructor; instances can then be created with newInstance and initialised with init. The problem with this is that it allows uninitialised instances to exist; this can be addressed using the EssencePattern.
- Define the standard constructor in each implementing class and just call it reflectively. The problem with this is that it has less type safety, and reflection may be slow.