OOP Simple Factory & Factory Method Pattern Page 4
logger.info(
"this Logger is really a " + logger.getClass().getName() );
slf4j can use the JDK java.util.logging classes, the well-known Log4J logger, "simple" logging that
prints to System.out, or "No-op" logging (does nothing) as the underlying logging program. The choice
depends on which JAR file you include in your project: if you include slf4j-simple.jar it uses simple
logging, if you include slf4j-log4j12.jar it uses Log4J, etc. The LoggerFactory makes the decision at
run-time based on what if find on the classpath.
How to Dynamically "Program" a Factory?
To write a factory that can change the kind of objects it creates at runtime without changing the Java
code, there are several common techniques:
1. Register a concrete factory with the abstract factory class. The abstract factory chooses among
available concrete factories when an object is requested.
2. Dynamically load a factory class using configuration information from a properties file.
3. Use the ServiceLoader class (JDK 6 and above) to locate available service provider classes (classes
that implement a "service" interface). The ServiceLoader class uses information from JAR files (in the
META-INF/services directory) to locate available service provider classes. The JDBC drivers use this
mechanism.
Example:
Suppose we have an interface named Factory. We also have an AbstractFactory class with a static
method named getInstance( ) that returns a concrete Factory object:
Factory myfactory = AbstractFactory.getInstance( );
We can change the actual type of the object returned by getInstance( ) by having AbstractFactory read
the name of the actual factory class (at runtime) and create a new object of this factory class.
How does AbstractFactory get the name of the concrete factory to create? One way is to use a property,
either a system property or your own properties file. You can choose any property name (being careful to
avoid names of existing system properties). Let's use the property name factory.name.
We can create a load the new Factory class at run-time and create an object by using code like this:
public abstract class AbstractFactory {
public static Factory getInstance() {
String factoryclass =
System.getProperty( "factory.name" );
//TODO this may throw many exceptions. Catch them.
Factory factory =
(Factory) Class.forName(factoryclass).newInstance( );
return factory;
}
What is not shown above is code to catch exceptions, and there should be a "default" factory class to use
in case the factory.name property is not set or can't be used.