One of my home projects is a factory modeling system. It was created because I wanted to explore how to best model a manufacturing plant. A lot of the software that I create at work also deals with modeling a manufacturing plant, but I wanted to create my own that was free of a lot of the historical artifacts that infect the work system. My home project can be changed at a whim as my thinking evolves, something that could not be done at work for obvious reasons. In some of my other projects I had stumbled upon a new way of thinking about JPA, and I wanted to try it out on the factory modeling system. It turned out to be a major "aha" moment in my thinking about the factory model.
In a normal object model, I will most likely tie all the objects together in some sort of "universe". The universe contains the pieces and describes the global aspects of the model. If you want to have a model backed by a database, often it is because of the scope of the model, so for instance, the factory model might have millions of part descriptions, either purchased or built, so having a universe in the traditional sense would not be feasible. So my original factory model had no universe, only discreet pieces that had no context, and were assumed to be global.
But the system needed a universe, if only to provide context for each of the pieces. My recent experience showed that things were much simpler if a universe was provided, so I looked at the factory model to try to figure out what I could use as a universe. Of course, what I came up with was a factory object that contained all of the pieces that I had so far in my model (not to be confused with the factory pattern).
The first problem with having a factory object, is normally I would want it to contain lists of all the sub-objects. That could be massive, and I didn't want to impose a limit on this system, even if it never is used in a massive scenario. Creating a limited system buys me no experience in creating a scale-able solution. I did it anyway, just to try it out. So my factory contained a number of 1-n relationships:
@ManyToOne(cascade=CascadeType.ALL)
List<Part> parts;
and then adding a part became a part of the factory class:
public Part addPart(String partName) {
Part ret = new Part(this, partName) {
parts.add(ret);
return ret;
}
This moved it away from being a static method of the Part class. Now the only static methods were for adding and finding the factory class. The nice thing about having a universe class, is now you can model at a level above the universe if need be. Making sure that the Factory wasn't a singleton, now I am free to model a company that has several manufacturing plants just by adding the next layer of universe (something that I had wanted to do originally but left it off for simplicity sake).
My problem of scale-ability remained, this system couldn't be used in a real setting due to it's limitation of maintaining a list of parts in the factory object. JPA has many advanced features of lazy-loading that might prevent that in many or most cases, but worst-case scenario was both possible and unacceptable. In addition, that means giving up control to the assumption that JPA will do what's best, which is good enough for simple cases, but not for production-ready systems. The problem dissolved away because I had the access to all of these pieces hidden behind the facade of the factory object. It was a simple matter of removing the List objects of the factory anywhere that they might be large (in my case I simply removed all of them), and then fix up any methods in the factory class to use JPA to substitute for the list. So my add function became:
public Part addPart(String partName) {
Part ret = new Part(this, partName) {
EntityManagerContainer().getEntityManager().persist(ret);
return ret;
}
I think the key is that you create the model fully implemented as Java objects, test it out on a small scale, and then identify the lists that might be too large to be easily instantiated, remove the lists and fix the methods as shown above.
After a lot of editing, this has worked beautifully, and simplified my tests and my usages of the system. I have already refactored my Vaadin GUI to use the new system, and it fit right into place. Next step, maybe I will try to put all of my AI beings from another project to work in a new factory, and see if they create anything. All code can be found here: https://www.kamradtfamily.net/svn/projects/trunk/erpsystem and here: https://www.kamradtfamily.net/svn/projects/trunk/erpgui