Class DynamicFactory

java.lang.Object
org.openscience.cdk.DynamicFactory

public class DynamicFactory extends Object
A factory class for constructing ICDKObject and IChemObject implementations. Instances can be created by registering a construction key (DynamicFactory.ConstructorKey) with a corresponding creator (DynamicFactory.Creator). In most cases a class can simply be registered by providing an interface and an implementation register(Class, Class). Internally the factory stores the object creators in a symbol table which allows near constant time access for all registered classes. In cases of a non-direct parameter match (e.g. Atom(Atom) can resolve to Atom(Element)) the constructor is matched by invoking find(ConstructorKey). If a constructor was found the new key will be registered with cache to avoid the overhead of finding the correct constructor again.


     // create an instance of the factory
     DynamicFactory factory = new DynamicFactory(5);

     // register some implementations
     factory.register(IAtom.class,          Atom.class);
     factory.register(IElement.class,       Element.class);
     factory.register(IAtomContainer.class, AtomContainer.class);

     // create an instance using the default constructor
     IAtom a1 = factory.ofClass(IAtom.class);

     // create an instance using a parametrised constructor
     IAtom c  = factory.ofClass(IAtom.class, "C");

     // using a custom creator to actually invoke a constructor
     // import static org.openscience.cdk.DynamicFactory.key;
     // import static org.openscience.cdk.DynamicFactory.BasicCreator;
     factory.register(key(IBond.class, IAtom[].class),
                      new BasicCreator<IAtom>(null) {
                          public IAtom create(Object[] objects) {
                              return new Bond((IAtom[]) objects);
                          }
                      });

 
It is not always convenient to specify a custom DynamicFactory.Creator for every construction type but the objects may still need some modification directly after creation. The factory provides DynamicFactory.CreationModifier which is invoked directly after object creation. This allows changing the default of creation. As an example it is possible to set a non-null charge on all atoms that are created.

      // import static org.openscience.cdk.DynamicFactory.CreationModifier;
     factory.register(IAtom.class, Atom.class,
                      new CreationModifier<Atom>() {
                          public void modify(Atom atom) {
                               atom.setFormalCharge(0);
                          }
                      }));
 
It is also possible change the object creation based on the input parameters.

 factory.register(key(IAtom.class, String.class),
                  new DynamicFactory.BasicCreator<IAtom>() {

                      public IAtom create(Object[] objects) {
                          String symbol = (String) objects[0];
                          return "R".equals(symbol)
                                      ? new PseudoAtom(symbol)
                                      : new Atom(symbol);
                      }
                  });

 factory.ofClass(IAtom.class, "C"); // IAtom
 factory.ofClass(IAtom.class, "R"); // IPseudoAtom
 
Author:
John May
Source code:
main
Belongs to CDK module:
core
  • Constructor Details

    • DynamicFactory

      public DynamicFactory(DynamicFactory.InterfaceProvider interfaceProvider, int n)
      Create a new default factory with an expected number of registered classes and an interface provider. The interface provider is used when registering an implementation without a specified interface register(Class).
      Parameters:
      interfaceProvider - provides the interfaces of a given implementation class
      n - the expected number of constructors that will be stored.
      See Also:
    • DynamicFactory

      public DynamicFactory(int n)
      Create a new default factory with an expected number of registered classes and a default interface provider. The default interface provider simply invokes Class.getInterfaces() when registering an implementation without an explicit interface register(Class).
      Parameters:
      n - the expected number of constructors that will be stored.
  • Method Details

    • register

      public <T extends ICDKObject> boolean register(Class<? extends T> impl)
      Registers a class with the factory. The interfaces of the class will be checked to see if they are CDK interfaces before they are registered. This method is provided for utility but will register the implementation with all valid interfaces. If a restricted registration is required then the safer register(Class, Class) can be used.
      Parameters:
      impl - a concrete class
      Throws:
      IllegalArgumentException - thrown if a non-concrete class is registered
      See Also:
    • register

      public <T extends ICDKObject> boolean register(Class<T> intf, Class<? extends T> impl)
      Explicitly register a concrete class with a provided interface. The DynamicFactory.Creator will be automatically created for all public constructors.
      Parameters:
      intf - the interface class to register
      impl - the concrete class which should implement the interface class
      Returns:
      whether registration was successful
    • register

      public <S extends ICDKObject, T extends S> boolean register(Class<S> intf, Class<T> impl, DynamicFactory.CreationModifier<T> modifier)
      Explicitly register a concrete class with a provided interface and a given modifier. The DynamicFactory.Creator will be automatically created for all public constructors. The modifier is incorporated into the DynamicFactory.Creator and is invoked directly after instantiation.
      
            // import static org.openscience.cdk.DynamicFactory.CreationModifier;
           factory.register(IAtom.class, Atom.class,
                            new CreationModifier<Atom>() {
                                public void modify(Atom atom) {
                                     atom.setFormalCharge(0);
                                }
                            }));
       
      Type Parameters:
      S - interface type
      T - implementation type (must extend interface)
      Parameters:
      intf - the interface class to register
      impl - the concrete class which should implement the interface class
      modifier - modify a instance after creation
      Returns:
      whether registration was successful
    • register

      public <S extends ICDKObject, T extends S> boolean register(Class<S> intf, Constructor<T> constructor)
      Register a specific constructor with an explicit interface.
      
           // only register construction of IAtom using a string - Atom("C")
           factory.register(IAtom.class,
                            Atom.class.getConstructor(String.class));
       
      Type Parameters:
      S - interface type
      T - implementation type (must extend interface)
      Parameters:
      intf - the interface
      constructor - a constructor which builds the given interface
      Returns:
      whether the constructor was registered
    • register

      public <S extends ICDKObject, T extends S> boolean register(Class<S> intf, Constructor<T> constructor, DynamicFactory.CreationModifier<T> modifier)
      Register a specific constructor with a creation modifier to an explicit interface.
      
            // only register construction of IAtom using a string - Atom("C")
            factory.register(IAtom.class,
                             Atom.class.getConstructor(String.class),
                             new DynamicFactory.CreationModifier<Atom>() {
      
                                 public void modify(Atom instance) {
                                    instance.setFormalCharge(0);
                                 }
                             });
       
      Type Parameters:
      S - interface type
      T - implementation type (must extend interface)
      Parameters:
      intf - the interface
      constructor - a constructor which builds the given interface
      Returns:
      whether the constructor was registered
    • register

      Register a constructor key with a defined DynamicFactory.Creator. The key defines the interface and parameters of the creation and the creator actually creates the object.
      
           // import static org.openscience.cdk.DynamicFactory.key;
           factory.register(key(IBond.class, IAtom[].class),
                            new BasicCreator<IAtom>(null) {
                                public IAtom create(Object[] objects) {
                                    return new Bond((IAtom[]) objects);
                                }
                            });
       
      Type Parameters:
      T - type of object that will be created
      Parameters:
      key - construction key, defines interface and parameter types
      creator - creates the actual object
      Returns:
      the registered creator - null if not registered
    • key

      public static DynamicFactory.ConstructorKey key(Class<?> intf, Class<?>... types)
      Creates a constructor key for use in accessing constructors. The key combines the interface and types in a single instance which we can then use in a map.
      Parameters:
      intf - the interface to build the key for
      types - the classes that the the constructor requires
      Returns:
      a constructor key which can be used to lookup a constructor
    • ofClass

      public <T extends ICDKObject> T ofClass(Class<T> intf, Object... objects)
      Construct an implementation using a constructor whose parameters match that of the provided objects.
      Type Parameters:
      T - the type of the class
      Parameters:
      intf - the interface to construct an instance of
      Returns:
      an implementation of provided interface
      Throws:
      IllegalArgumentException - thrown if the implementation can not be constructed
      IllegalArgumentException - thrown if the provided class is not an interface
    • ofClass

      public <T extends ICDKObject> T ofClass(Class<T> intf)
      Construct an implementation using the default constructor. This provides some speed boost over invoking ofClass(Class, Object...).
      Type Parameters:
      T - the type of the class
      Parameters:
      intf - the interface to construct an instance of
      Returns:
      an implementation of provided interface constructed using the default constructor.
      Throws:
      IllegalArgumentException - thrown if the implementation can not be constructed
      IllegalArgumentException - thrown if the provided class is not an interface
    • implementorsOf

      public <T extends ICDKObject> Set<Class<?>> implementorsOf(Class<T> intf)
      Access the registered implementations for a given interface.
      Type Parameters:
      T - the type of the interface
      Parameters:
      intf - an interface which has registered implementations in the factory
      Returns:
      set of implementation classes (empty if none found)
    • suggest

      public Iterator<DynamicFactory.ConstructorKey> suggest(Class<?> intf)
      Provides a list of all possible constructor keys for the provided interface.
      Parameters:
      intf - an interface to find all constructors for
      Returns:
      an iterator of constructor keys