Since you handwaved over "a much better design exists," I thought I'd give an example.
So, you have an app deployed to seven customers. The typical pattern is you develop an app for a first customer. It is then sold to subsequent customers, doing the least possible to make it work. In this case, as I have seen in the past, you have a properties file, saying which classes to use and which configuration options the customer has available.
These are then loaded up, as global state, so that your code can ask, "Does this application have Widget Processing capabilities?" and gets the answer for its code path. Consider:
if (AppProperties.getInstance().hasWidgetProcessing() {
process(widget);
}
Now, the problems here are pretty obvious. Since you're depending on a single file, your testing is a bear. Getting to the various codepaths is nigh impossible. Ideologically, it's bad design because your software has a bunch of if or switch statements in the code to decide what it should really do.
Now, what would make this code better? Well, you could start with taking all your Widget Processing capabilities and putting them in their own object or package. Then, instead of the above, your code looks like this:
public class WidgetImpl implements Widget {
private WidgetProcessor widgetProcessor;
public void process() {
widgetProcessor.process(this)
}
public void setWidgetProcessor(WidgetProcessor wp) {
this.widgetProcessor = wp;
}
}
In your main code:
widget.process();
WidgetProcessor has two (or more) implementations, in this case: RealWidgetProcessor and NullWidgetProcessor. NullWidgetProcessor just returns without doing anything.
Now, how does your Widget get the proper widget processor? Dependency injection. http://code.google.com/p/google-guice/wiki/Motivation?tm=6 has a pretty good explanation.
Improvements on the design are welcomed, as always. :) Though for simplicity's sake I was trying to keep code to a minimum. Now, speaking of code, my main issue with dependency injection is that the code baloons, especially in java. DI as a pattern makes me feel like there's something missing in current language implementations that would make this more elegant. Aspect-oriented programming was one try at it, but it seems that the cure is worse than the disease in that case.
I should mention that another alternative is to write a domain specific language, which is what a Lisper or Rubyist would advocate. That way, you put together each instance like play-doh. (a la http://weblog.jamisbuck.org/2008/11/9/legos-play-doh-and-pro... )
So, you have an app deployed to seven customers. The typical pattern is you develop an app for a first customer. It is then sold to subsequent customers, doing the least possible to make it work. In this case, as I have seen in the past, you have a properties file, saying which classes to use and which configuration options the customer has available.
These are then loaded up, as global state, so that your code can ask, "Does this application have Widget Processing capabilities?" and gets the answer for its code path. Consider:
Now, the problems here are pretty obvious. Since you're depending on a single file, your testing is a bear. Getting to the various codepaths is nigh impossible. Ideologically, it's bad design because your software has a bunch of if or switch statements in the code to decide what it should really do.Now, what would make this code better? Well, you could start with taking all your Widget Processing capabilities and putting them in their own object or package. Then, instead of the above, your code looks like this:
In your main code: WidgetProcessor has two (or more) implementations, in this case: RealWidgetProcessor and NullWidgetProcessor. NullWidgetProcessor just returns without doing anything. Now, how does your Widget get the proper widget processor? Dependency injection. http://code.google.com/p/google-guice/wiki/Motivation?tm=6 has a pretty good explanation.Improvements on the design are welcomed, as always. :) Though for simplicity's sake I was trying to keep code to a minimum. Now, speaking of code, my main issue with dependency injection is that the code baloons, especially in java. DI as a pattern makes me feel like there's something missing in current language implementations that would make this more elegant. Aspect-oriented programming was one try at it, but it seems that the cure is worse than the disease in that case.