Page 3 of 3
File Name: PricingPlans.txt
1,string_interfaces.PricingPlan20 2,string_interfaces.PricingPlan1510 3,string_interfaces.PricingPlan8 4,string_interfaces.PricingPlan10
Now you can create a PricingPlanFactory class that will return an IPricingPlan instance that corresponds to the PlanId that is passed to it. The class reads and parses the text file into a Map so it can do easy lookups based on the PlanId. But note that you can change the PricingPlanFactory class to use a database or XML file without changing anything outside the class.
You can refactor the Customer class so it returns the IPricingPlan instance instead of a PlanId. This design is better than the Customer class returning a PlanId, because other classes won't have to know that they must pass the PlanId to the PricingPlanFactory() method. Those classes won't have to know anything about the PricingPlanFactory; they can simply use the IPricingPlan instance as needed. (I used poor design earlier because I felt it more easily illustrated my point.)
These changes are located in the pricing_plan_factory package of this article's source code. Check Resources for download.
Test class in each package. The following table describes what you'll find in those packages:| Package | Description |
|---|
| no_interfaces | Example with no interfaces. |
| hard_coded_interfaces | Example that uses interfaces, but the class names are hardcoded into the source. |
| string_interfaces | Example that uses interfaces and has class names as strings in the source. |
| pricing_plan_factory | Example that uses a text file to get the class names. |
One final note about possible class loader problems: Class loaders work unexpectedly sometimes. For example, if the class
that calls the forName() method is an extension, the CLASSPATH directories will not be searched for the class that is being dynamically loaded. If you want an in-depth discussion of this possible problem or
are getting unexpected ClassNotFoundExceptions, see information on Class.forName() in Resources.
Also, check out the sidebar at the end of this article for tips on versioning your interfaces to avoid eliminating dynamic extensions when your program changes: Versioning Your Extension Interfaces.
You should now have enough knowledge to use interfaces and dynamic class loading to make flexible programs. By example, I showed you how to use a text file to load new functionality to code that uses no interfaces. Experiment with the code, and see how you can extend it. Now you can create programs to which users (other programmers, other departments, or even outside customers) can make additions without needing your source code.