Constructor Object - Dieptranivsr/DroneIVSR GitHub Wiki

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.