From: John M. <jo...@eb...> - 2012-11-15 10:08:09
|
Hi All, I've been working on a more flexible factory for the last few days and thought I'd share the results. The factory makes the specification of the IChemObjectBuilders easier. One issue with the existing builders was the builder didn't actually know which implementation was for what interface. This means when an implementation wasn't found, the suggestions message would try loading a class by name. This turned out to actually cause a recent test failure [commit]. It was also difficult to register new implementations for an interface. You could also imagine you may want to create your own domain, such as, an Atom which are backed by json or an AtomContainer which stores atoms in an adjacency matrix. It's easier to explain with an example: https://gist.github.com/4077684 (or see example below). Okay, but isn't this all very slow… well looks look at the actual time taken to create each object. For IAtom with a default constructor we fall in-between the static constructors and the current builders. We can optimise this by using the BasicCreator as I show in the example http://microbenchmarks.appspot.com/run/joh...@gm.../benchmark.Atom_Default_Instantiation How about Atom("C") - this increase for the factory is because Atom("C") looks up the atomic number in the periodic table http://microbenchmarks.appspot.com/run/joh...@gm.../benchmark.Atom_C_Instantiation These are of course very small time scales but the Atom is quite high up in the current builder decision tree. What happens if we benchmark an object right at the bottom of the decision tree - say AdductFormula? http://microbenchmarks.appspot.com/run/joh...@gm.../benchmark.AdductFormula_Default_Instantiation You can see the static and new factory times for AdductFormula are equivalent to the Atom benchmarks (around 20/30 ns respectively) and this doesn't change depending on which object you create. class CustomChemObjectBuilder implements IChemObjectBuilder { private final DynamicFactory factory = new DynamicFactory(200); public CustomChemObjectBuilder() { // basic registration factory.register(Element.class); // discovers Element is an instance of IElement, alternatively... factory.register(IElement.class, Element.class); // register Element with IElement explicitly // only register IElement as creatable via Element("symbol") constructor factory.register(IElement.class, Element.class.getConstructor(String.class)); // advanced registration // the key tells us the interface and the required parameters for construction // the second part actually does the creation, for the examples above the 'Creator' // is automatically built using reflection but we can gain a minor speed improvement // and can customise construction using an anonymous class factory.register(key(IElement.class, String.class), new BasicCreator<Atom>(Atom.class) { public Atom create(Object[] objects) { return new Atom((String) objects[0]); } }); // above is a bit of pain, what if I don't actually want to do the creation but I do // want to modify the element right after it's created. // this example sets a UUID for all construction methods factory.register(IElement.class, Element.class, new DynamicFactory.CreationModifier<Element>() { public void modify(Element element) { element.setID(UUID.randomUUID().toString()); } }); } /** * @inheritDoc */ @Override public <T extends ICDKObject> T newInstance(Class<T> clazz, Object... params) { // simply delegates the call return factory.ofClass(clazz, params); } } Just preparing the patch tracker now. Many thanks, J |