System Sort
Usage:
The System Sort program can be run in two different modes – text based and through a GUI. The text version takes its input through standard in, so it should be run as follows:
java SortMain [-r | -f # | -c # | -i | -n] < examplefile.txt
To run the GUI version of the program use:
java SortMain –g
The GUI version has a button that allows you to browse for the text file you would like to use as input. Choose your options, then click the “sort” button. Much like the command line version, this can only be run (sorted) once, then the program must be exited. The GUI mainly is to demonstrate the Decorator Pattern, not to be used as a viable software package.
Basic Organization:
The data is pulled in from either standard input or a text file (as explained above). The data is brought in with the Input class. This input class stores all of the lines in a character buffer. We then create and Access_Table that holds LinePtrs. The members of the LinePtrs class are just integers indicating how far into the character buffer a line or field starts. This is our workaround for not being able to set aside an exact place in memory and use pointers to it as we would in C++.
The Access_Table is masked beneath the Sort_AT_Adapter to allow the sort to use its own standard functions without knowledge of how the AccessTable works. Comparison operators are a good example of the types of functions in the adapter class that allows the interface between SystemSort and Access_Table.
The SystemSort and Options objects have single instantiations. The Options object holds the user specified options and the root compare function.
The Sort is done as a QuickSort. This quicksort will sort any objects implemented from the “Sortable” interface. So we caused our LinePtrs to implement Sortable and define the virtual function from Sortable for comparison.
Classes:
SortMain – the main program
SortGUI – the graphical user interface for SortMain
DArray – a dynamic array
Input – class for reading in data from stream or file
LinePtrs – pointers into a memory buffer
Options – global user options used for the program
Sort – abstract class for ordering methods
QuickSort – efficient sorting method
Pivot- pivot choosing strategy
PivotLast – chooses the last element in the array past to it
Access_Table – holds a DArray of LinePtrs, and the data buffer
Sort_AT_Adapter – wrapper to adapt Access_Table to the Sort
Sortable – object that can be sorted
SystemSort - main system object
Pattern Usage:
Façade
The best representation of the Façade pattern is use of the .print() function. The access table is hidden so that the user doesn’t have to do the job of going through the access table and LinePtrs to print individual lines. Instead, print masks the task behind the easier to user print() function. The Façade Pattern is meant to be used to hide complex details by giving a higher-level interface, which is exactly what happens here.
Adapter Pattern
The Adapter Pattern is used extensively to allow classes to interface with one another where they otherwise could not. The intent of the Sort_AT_Adapter pattern is to allow the calls that Sort intends to use (such as compare()) to be translated into the calls that the Access_Table class uses. This was explained extensively in the previous homework assignment.
Another good example is the “toString” function in many of the classes. For example, we can call:
System.out.println(SystemSort->instance());
The instance of SystemSort can be printed because the toString function is overloaded to call the toString on the Sort_AT_Adapter, and so on, until we reach the table where we can access the data and return the appropriate string. The access table is hidden behind a simple print call to a SystemSort object.
We used this yet again in the QuickSort class to allow it to sort anything of type “Sortable”. This way the QuickSort did not need to know that is was sorting LinePtrs, because the Sortable interface was extended by LinePtrs.
Singleton
The Singleton pattern is meant to force a single instance of classes that we use globally. The SystemSort and Options classes have an instance() method that returns the one and only instance of these classes. The first call to instance will create this object (which has a static member), and subsequent calls make use of this object and will not allow further instantiations. See observations for more information.
Strategy
The strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it. The QuickSort class implements a Pivot class that chooses a pivot for the given array in the quicksort algoritihim. This class can be replaced with any method for finding a pivot. Currently we are using the PivotLast class as our strategy.
Double-Checked Locking Optimization Pattern
This pattern was not used here, because java inherently made it unnecessary. The Singleton objects are already capable of preventing any race condition problems. See observations for more information.
Decorator Pattern
This was our additional pattern that we applied to the SystemSort program. The Decorator Pattern’s purpose is to attach additional responsibilities to an object dynamically and to provide a flexible alternative to subclassing for extending functionality. Our GUI lets you choose different input files, and more importantly different options flexibly while the program is running. The use can actually see the input file in the text area, and then can make decisions as to which fields/columns will be sorted and in what fashion.
Bridge Pattern
In the C code, the “<” operator was overloaded for LinePtr objects. Actually, one set of code used comparison between LinePtr objects directly, where the other set used the compare function with actual pointers to places in memory. In our code, we had the compare function in the Options class, and we passed the compare on to strings created from the locations we passed to compare(). That is, we passed the integers that indicated where in the char buffer each field started to compare(). Compare constructed strings from these characters and called an appropriate function to compare the strings based on which options the user chose. So the comparison is different depending on options, but it does so by adapting to another comparison function.
Factory
We took out the factory pattern, generally, because it would have required dynamic binding, which would have been much slower. The C++ code actually redefined the compare function to completely turn it into another function. We did something more along the lines of the Bridge and Adapter patterns by passing on the comparison to different functions depending on user options.
Observations
Java made the implementation of some classes easier than corresponding C++ classes. For instance C++ requires lazy instantiation for variables when doing the singleton pattern. In Java we can create data members as static final. Java is sure to instantiate this when the class is created. Therefore the double-checked locking optimization is also not required because there is no race condition. SystemSort.java has examples of where this happens in the source code.
Class Diagram: