Michael Coughlan
Page 64
• It is a closed subroutine.
• It can be called from any other module in the system.
• It has the potential of being independently compiled.
Although structured programming introduced a number of criteria for decomposing a system into modules, the main criteria for judging the quality of a module were module strength and module coupling (see Table 19-1).
1 On the Criteria to Be Used in Decomposing Systems into Modules. Commun. ACM 15, no. 12 (December 1972).
2 Wayne P. Stevens, Glenford J. Myers, and Larry L. Constantine. “Structured Design,” in Classics in Software Engineering, ed. Edward N. Yourdon (Upper Saddle River, NJ: Yourdon Press, 1979), 205–232.
519
Chapter 19 ■ OO-COBOL
Table 19-1. Module Strength and Module Coupling3
Module Coupling
Module Strength/Cohesion
Best
1
No direct coupling
Functional strength
and
2
Data coupling
informational strength
Better
3
Stamp coupling
Communicational strength
4
Control coupling
Procedural strength
Worse
5
External coupling
Classical strength
6
Common coupling
Logical strength
Worst
7
Content coupling
Coincidental strength
Module strength (sometimes called module cohesion) is a measure of the association between the elements of a module. Modules whose elements are strongly related to each other are regarded as more desirable than modules whose elements only have a weak or nonexistent connection. For instance, a functional-strength module is one in which all the elements combine to perform a single specific function or is one that coordinates subordinate modules such that they perform a single function. Modules such as ValidateCheckDigit, ValidateDate, GetStateCode, and GetCustomerRecord are functional-strength modules: they perform one specific task. On the other end of the scale, a coincidental-strength module is one in which the elements are only weakly related to one another and are more strongly related to the elements of other modules. Coincidental-strength modules are likely to be created when, for example, management mandates that a monolithic program be partitioned into subprograms, each 100 lines long.
Module coupling is a measure of the degree to which one module is connected to another. Modules that have low coupling are regarded as being more desirable than those that are highly coupled. A module with no direct coupling (the best) does not rely on data from other modules and provides no data to other modules. This data independence means this module is unlikely to be affected by bugs in other modules, and a bug in this module is unlikely to affect other modules.
In terms of module strength, a functional-strength module is often considered to be the best. However, this is not always the case. An informational-strength module has characteristics that may make it even more desirable than a functional-strength module. An informational-strength module has the following characteristics:
• It contains multiple entry points.
• Each entry point performs a single function.
•
All the functions are related by a concept, data structure, or resource that is hidden in the module
For instance, in the dictionary module shown in Figure 19-1, the dictionary is held in a table. The DictionaryModule has four separate entry points: one that allows words to be added to the dictionary, one that allows the dictionary to be searched for a particular word, one that prints the contents of the dictionary, and a final entry point that allows the definition of a dictionary word to be retrieved. Each entry point has functional strength but shares access to the table.
The advantage of this arrangement is that because knowledge of how the dictionary is represented is hidden in the module, you can change it without causing knock-on effects for the modules that use it. In Figure 19-1, the dictionary is held in a table; but if you decide to hold it as a dynamic structure or even an indexed file, the modules that use the dictionary will not be affected. This is the benefit of information hiding:4 the knowledge of the data structure, concept, or resource is isolated in a single module. It is the idea on which information-strength modules are based. 5
3 Glenford J. Myers, Composite/Structured Design (New York: Van Nostrand Reinhold, 1978).
4 David Parnas, “On the Criteria to Be Used in Decomposing Systems into Modules. Commun. ACM 15, no. 12 (December 1972).
5 Glenford J. Myers, Reliable Software through Composite Design (New York: Van Nostrand Reinhold, 1975).
520
Chapter 19 ■ OO-COBOL
Figure 19-1. Dictionary module with four entry points
Informational-Strength Modules in COBOL
The desirability of being able to create informational-strength modules is self evident. In COBOL, the combination of the IS GLOBAL phrase and contained subprograms seems to allow you create modules of this type. For instance, you could imagine that the dictionary module is an external subprogram that contains the AddWordToDictionary, SearchDictionaryForWord, PrintDictionaryContents, and GetWordDefinition subprograms and in which the
dictionary is held in a table made available to all the contained subprograms. Example 19-1 shows the outline of an attempt to create such an external subprogram. This arrangement reflects the structure of the informational-strength module shown in Figure 19-1. Unfortunately, the attempt to create an informational-strength module in this way is prevented by the rule that says a subprogram may only be called by its parent. In other words, the only program that can call AddWordToDictionary, SearchDictionaryForWord, PrintDictionaryContents, and GetWordDefinition is
the containing program DictionaryModule. They can’t be called by any other program in the run-unit that wants to use the dictionary. This situation is illustrated in Figure 19-2, where the program UseDictionary is not permitted to call the subprograms contained in DictionaryModule. You might think the IS COMMON PROGRAM clause provides a solution to the problem, but unfortunately that clause only allows the sibling subprograms to call one another.
Example 19-1. Attempting to Create an Informational-Strength Module
IDENTIFICATION DIVISION.
PROGRAM-ID. DictionaryModule.
WORKING-STORAGE SECTION.
01 DictionaryTable IS GLOBAL.
02 DictionaryEntry OCCURS 1000 TIMES.
03 DictionaryWord PIC X(20).
03 WordDefinition PIC X(1000)
IDENTIFICATION DIVISION.
PROGRAM-ID. AddWordToDictionary IS INITIAL.
PROCEDURE DIVISION USING WordToAdd, WordDefinition.
END PROGRAM AddWordToDictionary.
IDENTIFICATION DIVISION.
PROGRAM-ID. SearchDictionaryForWord IS INITIAL.
PROCEDURE DIVISION USING WordToFind, WordFoundFlag.
END PROGRAM SearchDictionaryForWord.
IDENTIFICATION DIVISION.
PROGRAM-ID. PrintDictionaryContents IS INITIAL.
PROCEDURE DIVISION.
END PROGRAM PrintDictionaryContents.
IDENTIFICATION DIVISION.
PROGRAM-ID. GetWordDefinition IS INITIAL.
PROCEDURE DIVISION USING WordToFind, WordDefinition.
END PROGRAM GetWordDefinition.
END PROGRAM DictionaryModule.
521
Chapter 19 ■ OO-COBOL
Figure 19-2. COBOL only allows a subprogram to be called by its parent
The only way any kind of informational-strength module can be achieved is for UseDiction
ary to call the
external subprogram DictionaryModule and for DictionaryModule to call the appropriate subprogram, as shown in Figure 19-3. To do this, UseDictionary has to pass a code to DictionaryModule to tell it which of the subprograms to use; and the parameter list passed to DictionaryModule has to be wide enough to accommodate the needs of the contained subprograms. This means even when PrintDictionaryContents is called, you must pass WordToAdd, WordToFind, WordFoundFlag, and WordDefinition as parameters. The problem with this solution is that although you may have created a kind of informational-strength module, the programs UseDictionary and DictionaryModule are now control coupled. The exposure to unnecessary data is not particularly egregious in this example, but it might prove a serious drawback if the contained programs had more significant data needs.
Figure 19-3. Workaround to create an informational-strength module in COBOL
522
Chapter 19 ■ OO-COBOL
The workaround to the problem of creating an informational-strength module in COBOL is not very satisfactory.
Module coupling has been traded for module strength. A kind of informational-strength module has been created, but at the expense of control coupling the DictionaryModule and UseDictionary programs.
When you come to use DictionaryModule, you may discover another limitation: there is only one instance of
the dictionary. This means you cannot use the DictionaryModule to create specialized dictionaries for acronyms, networking terms, or slang words without running the program multiple times.
OO-COBOL
OO-COBOL provides a solution to many of the problems outlined so far. In OO-COBOL, you can create a class in which to hide the implementation details of the dictionary, and you can create methods to put words into the dictionary and retrieve word definitions from the dictionary. In addition, a class-based solution goes one step beyond the informational-strength module because it allows you to create instances of the dictionary. This means you can create a dictionary to hold acronyms, a dictionary to hold networking terms, or even a dictionary to hold slang words.
The UseDictionary Program
Listing 19-1 uses OO-COBOL to create a Dictionary class and shows how it can be used to create and use multiple instances of dictionaries. Once you have seen an example program and have a feel for how OO is implemented in COBOL, I introduce the topic more formally. I have kept the Dictionary class short by only implementing the AddWordToDictionary and PrintDictionaryContents methods as well as the internal method SetDictionaryName.
Listing 19-1. COBOL Program that Uses the Dictionary Class
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing19-1.
AUTHOR. Michael Coughlan.
*UseDictionary program
REPOSITORY.
CLASS DictionaryCls AS "dictionary".
DATA DIVISION.
WORKING-STORAGE SECTION.
01 AcronymDictionary USAGE OBJECT REFERENCE DictionaryCls.
01 NetworkDictionary USAGE OBJECT REFERENCE DictionaryCls.
01 SlangDictionary USAGE OBJECT REFERENCE DictionaryCls.
01 CurrentDictionary USAGE OBJECT REFERENCE.
01 WordToAdd PIC X(20).
88 EndOfInput VALUE SPACES.
01 WordDefinition PIC X(1000).
PROCEDURE DIVISION.
Begin.
INVOKE DictionaryCls "new" USING BY CONTENT "Acronym Dictionary"
RETURNING AcronymDictionary
INVOKE DictionaryCls "new" USING BY CONTENT "Network Dictionary"
RETURNING NetworkDictionary
523
Chapter 19 ■ OO-COBOL
INVOKE DictionaryCls "new" USING BY CONTENT "Slang Dictionary"
RETURNING SlangDictionary
SET CurrentDictionary TO AcronymDictionary
DISPLAY "Fill the Acronym dictionary"
PERFORM FillTheDictionary WITH TEST AFTER UNTIL EndOfInput
SET CurrentDictionary TO NetworkDictionary
DISPLAY "Fill the Network dictionary"
PERFORM FillTheDictionary WITH TEST AFTER UNTIL EndOfInput
SET CurrentDictionary TO SlangDictionary
DISPLAY "Fill the Slang dictionary"
PERFORM FillTheDictionary WITH TEST AFTER UNTIL EndOfInput
DISPLAY SPACES
INVOKE AcronymDictionary "PrintDictionaryContents"
DISPLAY SPACES
INVOKE NetworkDictionary "PrintDictionaryContents"
DISPLAY SPACES
INVOKE SlangDictionary "PrintDictionaryContents"
INVOKE SlangDictionary "finalize" RETURNING SlangDictionary
INVOKE NetworkDictionary "finalize" RETURNING NetworkDictionary
INVOKE AcronymDictionary "finalize" RETURNING AcronymDictionary
STOP RUN.
FillTheDictionary.
DISPLAY "Enter a word to add (press return to end) - " WITH NO ADVANCING
ACCEPT WordToAdd
DISPLAY "Enter the word definition - " WITH NO ADVANCING
ACCEPT WordDefinition
INVOKE CurrentDictionary "AddWordToDictionary"
USING BY CONTENT WordToAdd, WordDefinition.
Listing 19-1 uses the dictionary class to create three instances of the dictionary: one to hold acronyms, one for network terms, and the third to hold slang words. The program demonstrates that three instances of the dictionary have been created by filling each with relevant words and then displaying the words in each dictionary.
It is interesting to note how little the language has been changed to accommodate the syntax required to write OO-COBOL programs. In Listing 19-1, the first difference between this and an ordinary COBOL program is the REPOSITORY paragraph. This paragraph lists the classes used in the program. The AS clause specifies the external name for the class.
The second difference is the USAGE OBJECT REFERENCE clause, which is an extension of the USAGE clause that allows you to specify that a data item is capable of holding a reference (handle) to an object. In the program, three data items capable of holding references to dictionary objects are created, and a fourth is created that can hold a reference to any object. I could have made this last a dictionary reference also, but I wanted to show that you can create object-reference data items that are not bound to a particular type of object.
524
Chapter 19 ■ OO-COBOL
The first thing done in the PROCEDURE DIVISION is to create three instances of the dictionary and assign their references (handles) to the appropriate object-reference data item. This is done by using the INVOKE verb to execute the new method in the dictionary class (or, to describe it in OO-COBOL terms, the INVOKE verb is used to send the new message to the dictionary class.) Because there are three instances of the dictionary, you need to tell each instance its name, so the name of the dictionary is passed to new as a parameter. The new method creates an object instance and places a reference to the instance (the object handle) in the object-reference data item.
At this point, three instances of the dictionary object have been created, and the next step is to fill each dictionary with the appropriate words. I could have done this by repeating the code in the paragraph FillTheDictionary three times and each time targeting a different dictionary (this is what I do to display the contents of each dictionary). But I wanted to create one piece of code to handle all three dictionaries. To do this, instead of referring to a specific dictionary in the FillTheDictionary paragraph, I refer to the CurrentDictionary object reference and then, just before the FillTheDictionary paragraph is performed, move the appropriate dictionary object reference to CurrentDictionary.
When the dictionaries have been filled with words, the contents of the dictionaries are displayed. This is done by sending the PrintDictionaryContents message to the appropriate dictionary object.
Finally, the storage used by the dictionaries is released by sending a finalize message to the appropriate dictionary object. This is often a vital step because if the program ends with
out destroying the object, the memory allocated to the object is still allocated but the object references that allow you to access the object in memory are lost.
The Dictionary Class
Listing 19-1 showed how to use the dictionary class to create and use dictionary object instances. Listing 19-1-cls (identified as Listing 19-1-cls.cbl in the online sources) shows how to define the dictionary class.
Listing 19-1-cls. The Dictionary Class
CLASS-ID. DictionaryCls AS "dictionary"
INHERITS FROM Base.
AUTHOR. Michael Coughlan.
REPOSITORY.
CLASS Base AS "base"
CLASS DictionaryCls AS "dictionary".
FACTORY.
METHOD-ID. New.
LINKAGE SECTION.
01 TestObject-lnk OBJECT REFERENCE.
01 DictionaryName PIC X(20).
PROCEDURE DIVISION USING DictionaryName RETURNING TestObject-lnk.
Begin.
*Create a new dictionary object by invoke "new" in the base class
INVOKE SUPER "new" RETURNING TestObject-lnk.
*Set the dictionary name in the dictionary object
INVOKE TestObject-lnk "SetDictionaryName"
USING BY CONTENT DictionaryName
EXIT METHOD.
END METHOD New.
END FACTORY.
525
Chapter 19 ■ OO-COBOL
OBJECT.
WORKING-STORAGE SECTION.
*Items declared here are visible only to methods of this
*instance. They have state memory.
01 DictionaryTable.
02 DictionaryEntry OCCURS 0 TO 1000 TIMES