The solution with object-oriented architectural style decomposes the system into six modules:
Contrary to the main/subroutine solution, in the object-oriented solution the data is not shared between the computational components. Instead, each module provides an interface that permits other components to access data only by invoking methods in that interface. For example, LineStorage module provides the public interface that allows other modules to set character in a particular word in a particular line, read a specific character, read, set or delete a particular word in a specific line, read whole line at once, etc.
Class diagram is the result of static analysis, architectural design, and class design of an object-oriented software system. Usually, we develop class diagrams by using Unified Modeling Language (UML). Such UML class diagram includes the following information:
Each module from the architectural design maps exactly onto one
class. Thus, there exist KWIC class (Master Control
module), Input class, Output class,
LineStorage class, CicrularShifter class and
Alphabetizer class. Each class is represented as a
rectangle box, having three horizontally arranged sub-boxes. The name
of each class is written in the top sub-box.
Public interface of each class is written into the bottom sub-box, as
a list of method declarations. The plus (+) sign in front of a method
name means that the method is defined as public and may be invoked by
objects of other classes. The argument list is written within
parenthesis. Each argument is represented with the name, its type and
the direction in which the argument is passed. If there is no
direction modifier that means that this method takes this argument,
and if there is out modifier that means that the method
returns this argument as a return value to the calling object. For
example, +getChar(out c:char, position:int, word:int,
line:int) method from the LineStorage class takes
as arguments three integere values: position of the character, index
of the word, and index of the line, and returns the value of that
character.
Instance variables (attributes) of a class are shown in the middle
sub-box. The minus (-) sign in front of an instance variable means
that the variable is defined as private and may not be manipulated by
other objects directly. Instead, the public interface of the class
should be applied to do so. That is completely in accordance with
object-oriented principles of data encapsulation and information
hiding. After the minus sign, the name and the type of a particular
instance variable are shown. For example, the LineStorage
class has one private instance variable: lines_. This
instance variable is of type ArrayList, and holds a list
of lines.
Finally, we have a number of associations between some of the
classes. A directed association means that the originating class has
as an instance variable an object of the associated class. For
example, the Alphabetizer class has an association with
the CircularShift class. That means that an object of the
Alphabetizer class has as an instance variable an object
of the CircularShift class. This variable is also
depicted in the middle box of the Alphabetizer class. We
can spot there shifter_ variable, which is of type
CircularShifter. The numbering at each association end
means that exactly one object of the Alphabetizer class
holds exactly one object of the CircularShifter class.
In UML dynamic (interaction) diagrams describe how group of objects collaborate to execute a certain task in a running program. In other words these diagrams show graphically the processing algorithm and the dynamic behaviour of a running system. Sequence diagram is a special type of dynamic diagrams that describes the time sequence of method invokations on the run-time:
An instance of the KWIC class controls the execution of
the program. Firstly, parse method of an instance of the
Input class is invoked. This method takes as arguments
the name of the file containing lines, and an instance of the
LineStorage class to store the data.
The parse method reads the data from the file. For each
line in that file it creates a new line in the
LineStorage by invoking its addEmptyLine
method. To add words to the new line Input
object invokes addWord method on
LineStorage. The iterative nature of this process is
simbolized in the diagram with * sign in the front of the
addWord method name.
Once when the parsing of lines is finished the KWIC
object invokes the setup method of the
CircularShifter instance. The single argument for this
method is LineStorage holding the lines. The
CircularShifter object iterates through all lines in the
LineStorage and produces circular shifts of these lines.
At the next step the KWIC object invokes the
alpha method of Alphabetizer instance. This
method takes as an argument the CircularShifter
object. It then sorts shifts alphabetically, retrieving each of them
from CircularShifter object by invoking its
getLineAsString method.
Finally, the KWIC object invokes the print
method on Output instance. This method takes as an
argument the Alphabetizer object from the previous
step. It iterates then through all lines from the
Alphabetizer object by invoking
getLineAsString method. Notice that this method just
forwards the request to the CircularShifter object to
retrieve the data. Of course, the forwarded request does not include
the original index, but the sorted one. When the print
method returns, the execution of the program is finished.