Re: factory objects (idle thoughts)
Stefan Ram wrote:
I read this in the world wide web:
?Having dismissed constructors and static factories, it
seems we need to define a factory class whose instances
will support an interface that includes a method that
constructs the desired objects. How will you create the
factory object? By calling a constructor? Or by defining
a meta-factory? After how many meta-meta-meta- ..
meta-factories do you give up and call a constructor??
Your question seems to be "how do you start?" One can imagine a large
and complicated framework, but maybe something simple is the best place
to start. Basics like use of interfaces and design basics like
Inversion of Control are always reasonable places to start.
I say the same thing as Tom -- a class name in a config file is the
ultimate form of Inversion of Control (specifically Dependency
Injection) and is something to at least consider. So how do you start that?
Assuming your application has more than one property -- more than one
config string -- it seems reasonable that we can start like this:
public interface Application {
void startUp( java.util.Properties props );
}
Now you have a mechanism to call Class#forName, using the property
object. You can make your factory by fetching a name out of this
Properties object and calling forName(). You can also configure any
other part of the application by defining a key-value pair in the
Properties.
But how does this method start? What about the code that runs before
startUp()? There's no need to invent further complexities at this
point, in my opinion. As someone said in response to another question,
"just code it."
public class Bootstrap
{
private Bootstrap() {}
public static void main( String... args )
throws IOException, ClassNotFoundException,
InstantiationException, IllegalAccessException
{
// load properties file
Reader propReader = new BufferedReader( new InputStreamReader(
Bootstrap.class.getResourceAsStream(
"/application.properties" ), "UTF-8" ) );
Properties props = new Properties();
props.load( propReader );
// create and start application
String appName = props.getProperty( "main.application" );
Application app = (Application) (Bootstrap.class.forName(
appName ).newInstance());
app.startUp( props );
}
}
This isn't nice to test (and I didn't test it), but once tested, there
should be no need to change it. We load a properties file called
"application.properties" from the root of the Jar file or classpath,
then uses it to find the application to run. We also pass in the
properties themselves so the application can use them to configure itself.
There are problems here. We really should do something about those
exceptions that the method throws (the proverbial exercise for the
reader ;) ). And it really needs some user friendly error trapping,
just in case -- we should really wrap that call to startUp() in a
try-catch, in case the application exits with an Exception.
But here we have a super simple application framework that can be used
to inject all behaviors into a new application (including the class name
of the application itself) and is also fairly easy to test due to its
relative simplicity.
There's no need to make a "factories all the way down" framework. Just
start at the obvious place, and if it works, great. If it falls short,
refactor to make the simplest thing that will work.