- Overall Application
- Ferret Interface
- Implementing the Ferret
- Instantiating the Ferret
- A Second Ferret
- Introducing the Factory
- Enabling the Factory to Use Different Classes
- Allowing the User to Choose at Runtime
- Moving On from Here
Allowing the User to Choose at Runtime
The ultimate goal is to have an application that is completely implementation-independent, and allows the user to choose (or not choose, as the case may be) at runtime.
To do that, it's customary to use system properties because the user can set them from the command-line, and they'll carry through to the application. (System administrators can also set default properties.)
First, let's look at updating the FerretFactory to look for the org.chase.Ferret property, as shown in Listing 10.
Listing 10 Checking for the System Property
package org.chase.research; public class FerretFactory { public Ferret newFerret () { Ferret theFerret = null; String classname = System.getProperty("org.chase.ferret"); if (classname == null) { classname = "org.chase.ferrets.GoogleFinder"; } theFerret = this.newFerret(classname); return theFerret; } public Ferret newFerret (String classname) { Ferret theFerret = null; try { theFerret = (Ferret) Class.forName(classname).newInstance(); } catch (Exception e) { theFerret = new org.chase.ferrets.GoogleFinder(); } return theFerret; } }
In this case, the no-argument version of the method checks for a system property value; and if it doesn't find one, it uses the default: org.chase.ferrets.GoogleFinder. In either case, it then uses the newly retrieved string to call the second version of the method and actually instantiate the class, which it returns to the application.
So what does this mean for our application?
Well, we can go on specifying the name of the class, as we did in the previous example, or we can take out the argument, as shown in Listing 11, and let the user choose from the command line, as we'll see in the minute.
Listing 11 Final ResearchProject.java File
import org.chase.research.Ferret; import org.chase.research.FerretFactory; public class ResearchProject { public static void main(String[] args) { if (args.length > 0) { String searchTerm = args[0]; FerretFactory ferretFactory = new FerretFactory(); Ferret theFerret = ferretFactory.newFerret(); System.out.println("Getting Results ..."); theFerret.find(searchTerm); int numResults = theFerret.getNumResults(); if (numResults > -1) { System.out.println("\n========================="); System.out.println("Number of hits: "); System.out.println("========================="); System.out.println(numResults); } else { System.out.println("Result count not available."); } System.out.println("\n========================="); System.out.println("First Result: "); System.out.println("========================="); System.out.println(theFerret.getFirstResult()); System.out.println("\n========================="); System.out.println("All available results: "); System.out.println("========================="); System.out.println(theFerret.getResults()); } else { System.out.println("You must enter a search term."); } } }
As before, there's no argument for newFerret(), so (all things being equal) the FerretFactory will produce a GoogleFinder Ferret.
If, on the other hand, we want to specify a GoogleSpecificFinder-variety Ferret at runtime, we can do it by adding a new parameter:
java -Dorg.chase.ferret=org.chase.ferrets.GoogleSpecificFinder ResearchProject hyperdriveNote that the lack of space after the -D is not a typo. This is what tells the system that what follows is a system property declaration. Running the application this way uses the GoogleSpecificFinder class for the search.