I have a factory class that serves out a bunch of properties.
Now, the properties might come either from a database or from a properties file.
This is what I've come up with.
public c开发者_Python百科lass Factory {
private static final INSTANCE = new Factory(source);
private Factory(DbSource source) {
// read from db, save properties
}
private Factory(FileSource source) {
// read from file, save properties
}
// getInstance() and getProperties() here
}
What's a clean way of switching between these behaviors based on the environment. I want to avoid having to recompile the class each time.
Dependency Injection is the way to do it.
- Overview: http://en.wikipedia.org/wiki/Dependency_injection
- Spring DI: http://www.vogella.de/articles/SpringDependencyInjection/article.html#usageannotations
- Guice DI: http://code.google.com/p/google-guice/
Generally, using dependency injection in your situation would look like this (example is for Spring DI, would look little different for Guice but the idea is the same):
public interface Factory {
Properties getProperties();
}
public class DBFactory implements Factory {
Properties getProperties() {
//DB implementation
}
}
public class FileFactory implements Factory {
Properties getProperties() {
//File implementation
}
}
public SomeClassUsingFactory {
private Factory propertyFactory;
public void setPropertyFactory(Factory propertyFactory) {
this.propertyFactory = propertyFactory;
}
public void someMainMethod() {
propertyFactory.getProperties();
}
}
//Spring context config
<!-- create a bean of DBFactory (in spring 'memory') -->
<bean id="dbPropertyFactory"
class="my.package.DBFactory">
<constructor-arg>
<list>
<value>Some constructor argument if needed</value>
</list>
</constructor-arg>
</bean>
<!-- create a bean of FileFactory (in spring 'memory') -->
<bean id="filePropertyFactory"
class="my.package.FileFactory">
<constructor-arg>
<list>
<value>Some constructor argument if needed</value>
</list>
</constructor-arg>
</bean>
<!-- create a bean of SomeClassUsingFactory -->
<bean id="MainClass"
class="my.package.SomeClassUsingFactory">
<!-- specify which bean to give to this class -->
<property name="propertyFactory" ref="dbPropertyFactory" />
</bean>
Then, in different environment you just swap your xml config file with some other file that sets the property to filePropertyFactory and you get it passed into the SomeClassUsingFactory.
Simply, don't use singletons.
"Parameterise from Above." Construct the required implementation at a place in the code where it makes sense. Pass the instance down to those objects that need it as they are constructed.
You could define something like:
public abstract Factory {
// define all factory methods here
public static Factory getFactory(FactoryType type, Object source) {
if (type == FactoryType.DB) {
return new DbFactory(source);
}
if (type == FactoryType.PROPERTIES) {
return new PropertiesFactory(source);
}
}
}
public DbFactory implements AbstractFactory { .. }
public PropertiesFactory implements AbstractFactory { .. }
- You can use
instanceof
instead of theenum
- if you want your factories to be singleton, replace instantiation (
new
) with a static method
精彩评论