218 Chapter 15 ■ Object-oriented programming Answers to self-test questions 15.1 public void moveDown(int amount) { y = y + amount; } 15.2 public int yCoord { get { return y; } } 15.3 Methods: creditAccount, debitAccount, calculateInterest Properties: currentBalance, name 15.4 class Stack { private Arraylist s = new Arraylist(); public void push(String item) { s.add(0, item); } public String pop() { String item = (String) s.get(0); s.remove(0); return item; } } 15.3 Suppose that you were asked to design a new programming language for software engineering: ■ select and justify a mechanism for encapsulation ■ select and justify a mechanism for modularity. 15.4 Explain what the term modularity means. Assess how well the following features of programming languages contribute to modularity: ■ methods ■ classes. 15.5 Assess the generics feature. 15.6 Argue for and against pointers in a programming language. 15.7 Argue for and against automatic garbage collection. BELL_C15.QXD 1/30/05 4:23 PM Page 218 Answers to self-test questions 219 15.5 class Bomb extends Sprite { private ImageIcon bombImage; public Bomb(int newX, int newY, int newSize) { x = newX; y = newY; size = newSize; bombImage = new ImageIcon("c:/bomb.jpg"); } public void display(Jpanel panel) { Graphics paper = panel.getGraphics(); bombImage.paintIcon(panel, paper, x, y); } public void move() { y = y - 20; } } 15.6 public int sum(ArrayList <String> list) { int total = 0; for (int i = 0; i < list.size(); i++) { total = total + Integer.parseInt(list.get(i)); } return total; } 15.7 Generics complicate the language. 15.8 There are many possible answers. Here are just two: 1. a file sort program, because you never know how long the file will be 2. A web browser program, because you do not know in advance how big a web page will be. 15.9 In an array, all items after the insertion point have to be moved down the array, a time-consuming process. In a dynamic structure, only the pointer in the immediately preceding item needs to be updated – a very fast operation. 15.10 Factor C++ Java reliability poor good development effort greater smaller performance faster unpredictable BELL_C15.QXD 1/30/05 4:23 PM Page 219 220 Chapter 15 ■ Object-oriented programming Smalltalk-80 is the Rolls Royce of object-oriented language. It is completely object- oriented – even control structures like repetition and if statements are objects. Like Java it supports single inheritance. Like Java it provides a large and compre- hensive library that the programmer uses and inherits from to provide facilities including windowing, graphics and data structures. The definitive book on Smalltalk-80: Adele Goldberg and David Robson, Smalltalk 80, the Language, Addison-Wesley, 1989. The definitive book on the Eiffel language. The first few chapters are a wonderfully clear exposition of the principles of OOP: Bertrand Meyer, Object-Oriented Software Construction, Prentice Hall, New York, 2000. Further reading • BELL_C15.QXD 1/30/05 4:23 PM Page 220 The programming of very large, complex software projects, or programming in the large, introduces many new problems for the software engineer. First, what are the characteristics of such software systems? The size of the code is an obvious factor. Large systems consist of tens of thousands of lines of source code; systems with hundreds of thousands of lines are not uncommon. Projects of this size must be developed by teams of programmers; for very large projects the programming team may consist of hundreds of programmers. Such systems are implemented over a long period of time and when completed are expected to undergo continual maintenance and enhancement over an extended lifetime. Many of the problems associated with such large projects are logistical, caused by the sheer size of the task and the number of personnel involved. Methodologies for man- aging such projects have been developed and are discussed in other sections of this book. Clearly, many software tools, other than the programming language being used, are required to assist and control the development of such large systems. A recent trend has been to integrate these software tools with a particular programming language to form an integrated software development environment. In this section we concentrate on support for programming in the large at the programming language level. 16.1 ● Introduction CHAPTER 16 Programming in the large This chapter: ■ reviews the facilities needed for large programs ■ explains the ideas of packages and their scopes ■ explains scopes for large software ■ explains using interfaces to describe the structure of software ■ explains using interfaces for interoperability ■ discusses separate compilation. BELL_C16.QXD 1/30/05 4:24 PM Page 221 222 Chapter 16 ■ Programming in the large It is useful to divide up the discussion into those features required to support pro- gramming in the small and those required to support programming in the large. By programming in the small, we mean those features of the language required to support the coding of individual program modules or small programs. In this catego- ry, we include the simplicity, clarity and orthogonality of the language, the language syntax and facilities for control and data abstraction. We reviewed these features in Chapters 14 and 15. By programming in the large, we mean those features of the language which sup- port the development of large programs. Here, we define a “large” program as one whose size or complexity dictates that it be developed by a number of programmers and which consists of a collection of individually developed program modules. In this category we include facilities for the separate compilation of program modules, fea- tures for controlling the interaction between program modules, high-level functional and data abstraction tools and programming environments or support tools associated with the language. What support can we expect from a programming language? The programmer’s chief tool in managing complexity is abstraction. Abstraction allows the programmer to keep a problem intellectually manageable. The programming language must therefore provide mechanisms which can be used to encapsulate the most common abstractions used by programmers: functional (or procedural) abstraction and data abstraction. The simplest mechanism, provided by nearly all programming languages, is the method, a program unit which allows the encapsulation of a functional abstraction. Programming in the large requires that higher-level abstraction primitives than the method be pro- vided. We have already met one such structure – the class. This helps considerably, but we need still higher-level structuring mechanisms. The use of abstractions promotes modularity which itself encourages the production of reusable code and promotes the notion of information hiding. Modularity and mod- ule independence are essential in an environment where individual modules will most often be developed by different programmers. The programming language can support development in multiprogrammer environments by providing mechanisms for hiding from a user irrelevant detail concerning the implementation of a module. Additionally, the interface between modules must be carefully controlled. It is essential to eliminate the possibility that the implementation of one module may affect another module in some unanticipated manner. This is also important when a system is being maintained or enhanced in some way. It must be possible to localize the effect of some system enhancement or error fix to specific modules of the system; side effects of changes should not propagate throughout the complete system. Clearly, many of these issues are as much system design issues as they are programming language issues. No program- ming language will solve the problems of a poor system design. On the other hand, the implementation of a good system design can be hampered if the implementation lan- guage is of limited expressive power. If components are to be developed independently, the programming language must also provide facilities for independent compilation. In addition, the language should provide strong type checking across component boundaries to ensure the consistency of calls to externally defined components. All the major modern programming languages BELL_C16.QXD 1/30/05 4:24 PM Page 222 16.2 Packages 223 for software engineering (C++, Ada, C# and Java) carry out such checks. Another acute problem in large programs concerns the handling of unexpected events during the execution of a program. Programming language features for exception handling are discussed in Chapter 17. In summary we can identify several needs for programming in the large: ■ to be able to see the overall structure of the system ■ to compile separately and link program modules ■ to be able to access software libraries, e.g. graphics or mathematical methods ■ to be able to reuse software components that have been created for one system as part of a new system – in order to reduce development costs ■ to provide facilities that support the construction of a large piece of software by a team. The idea of a class is to group together a set of methods and data that are related in some way. This then constitutes a programming unit that is bigger than a single method or data item. So instead of describing a large program as consisting of 50 methods and 10 data items, we can view it as a collection of, say, 10 classes. This is potentially easier to understand, design, code, debug, test and maintain. (Even worse, we could think of a program in terms of 10,000 lines of coding.) The next stage is to group classes into packages. Again, instead of thinking of a program as 100 classes, we can see it as a collection of 10 packages. The Java libraries provide thousands of useful classes. For convenience, the classes are grouped into packages. Here, for example, are some of the Java library packages with an outline of their contents: java.lang contains the classes that support the main features of the language like Object, String, number, exception and threads java.util these are useful utility classes, such as Random and ArrayList java.io text input and output streams for characters and numbers java.net classes that carry out networking functions, socket programming, interacting with the internet javax.swing this includes the classes to provide GUI components, such as buttons ( JButton), labels (JLabel) and sliders (JSlider). java.awt awt stands for Abstract Window Toolkit. The graphics methods, such as drawLine, are here. java.applet the classes provide support for Java applets (programs run from a web browser). 16.2 ● Packages BELL_C16.QXD 1/30/05 4:24 PM Page 223 224 Chapter 16 ■ Programming in the large UML provides a graphical notation for describing packages. Figure 16.1 shows a package named util which consists of three classes Random, ArrayList and Stack. Showing the contents of a package is optional. This notation is useful for visualizing the large-scale architectural structure of software. Packages represent the highest-level programming units, which ranges from the small size to the large, as follows: ■ statements ■ methods ■ classes ■ packages. The languages C++ and C# provide a mechanism termed namespaces that is similar to packages. We will now see how packages are used within a programming language. Java programs typically start with import statements, such as: import java.awt.*; import java.awt.event.*; import javax.swing.*; java.awt, java.awt.event and javax.swing are the names of packages. Each of these packages contains a number of useful classes. For example, the class JButton is in the package javax.swing. The import statements enable a program conveniently to use the classes provided by the packages. Because the import statement is present, we can simply refer to JButton 16.3 ● Using packages util Stack Random ArrayList Figure 16.1 A package diagram BELL_C16.QXD 1/30/05 4:24 PM Page 224 16.3 Using packages 225 In C and C++, a program almost always begins with an include declaration. For a system package the declaration is typically: #include <stdio.h> or, for a programmer’s own package: #include "myFile.h" The include statement is a directive to the compiler to include within the cur- rent source file a copy of the named file. A file with the suffix .h is, by convention, a header file and it is files of this type that normally appear in the include state- ment. A header file is a source code file that contains the declaration of the methods to be found within a package. These declarations are, in C terminology, the proto- types of the available methods – their names and parameters. The C and C++ lan- guages have a rule that a method has to be declared (textually) before it can be used. When a declaration like this is present, the program can refer to the methods with- in the package described and it will compile successfully. Subsequently the object code of the packages is linked. SELF-TEST QUESTION 16.1 Classes called Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday are grouped in a package called week. Write down the Java import statement that will be needed to use the class Friday. Write the statement to create an object friday of the class Friday. Write down the import statement that will be needed to use all the classes in the package. without difficulty. For example: JButton button = new JButton("go"); If the import statement was omitted, we could still use the class JButton, but we would need to refer to it by its full name – javax.swing.JButton. This would be inconvenient and cumbersome. Hence we see the value of the import statement. If we only need to import an individual class, say JButton, from within a package, we can spell it out: import javax.swing.JButton; Using * means that we want to import all the classes within the named package. So if we need to use more than one from a package, it is simpler to use the * notation. BELL_C16.QXD 1/30/05 4:24 PM Page 225 We have already seen how a program can access other packages using import or include statements. The issue is: What packages, methods and (rarely) variables are accessible to any given package? When you create and use packages, some new scope rules come into play. The essence is that classes within the same package can access each other very easily. When you write a method in Java, you specify that it is private, public, pro- tected or simply give it no prefix. The prefix determines who can access the method: public means that the method is available to all. private means that it is accessible only within the class. protected means that the method can be used by any subclass. If you give a method no prefix, it means that the method is accessible from anywhere within the same package, but inaccessible from outside. This is also true of classes, con- structors and variables. This means that the programmer can establish a close relation- ship between methods in the same package. This accords with the idea that classes in the same package are related to each other. 16.5 ● Scoping in large programs 226 Chapter 16 ■ Programming in the large Suppose a system consists of three groups of classes: 1. classes that handle the user interface 2. classes that access the database 3. classes that handle the central logic of the program. We create three packages, named gui, database and logic. Next we need to ensure that individual classes are in the correct package. In Java this is accomplished using the package statement written at the head of the class. So, if we have a class named Login that handles the login part of the GUI, we write the following at the head of the class: package gui; public class Login If you omit a package statement, it means that the class is placed, by default, in a package with no name. 16.4 ● Creating packages SELF-TEST QUESTION 16.2 A class named Backup is to be placed in a package named database. Write the package statement and the class heading. BELL_C16.QXD 1/30/05 4:24 PM Page 226 16.6 Interfaces 227 The structure of a large program is often derived by using some design method, as described in other chapters in this book. Typically the structure is described in a graph- ical notation, such as a class diagram. However, some programming languages enable this large-scale, or architectural, structure to be expressed within the programming lan- guage itself. In Java, for example, the specification of each class can be written in the programming language. The collection of specifications then constitutes a description of the architecture of the software. The notation used to describe these components is termed an interface or a module interconnection language. We will use the Java notation to illustrate how classes can be described. First, here is the description of a stack class. interface StackInterface { void push(int item); int pop(); } A user of the stack class does not need to know how it works, but knows how to call it. The stack might be represented as an array, a linked list or even (if it was large enough) as a file. This is abstraction at work. It frees the programmer from thinking about detail in order that they can concentrate on the bigger picture. The implemen- tation of the stack could be changed (because of performance improvement or the elim- ination of bugs), but any packages that use it would not be affected. The stack class could easily be reused in some other program because the interface to it is clean. 16.6 ● Interfaces SELF-TEST QUESTION 16.3 Suggest one drawback to this kind of specification. An interface can be compiled along with any other classes, but clearly cannot be exe- cuted. However, someone who is planning to use a class can compile the program along with the interface and thereby check that it is being used correctly. Once the classes that comprise a new software project have been identified and spec- ified, the classes can then either be written from scratch or retrieved from an existing library. A person who is implementing an interface can specify in the heading of the class that a particular interface is being implemented. For example, in Java: class Stack implements StackInterface Notice that the class as a whole is described as implementing the StackInterface interface. The compiler will then check that this class has been written to comply with the interface declaration, that is, it provides the methods push and pop together with their appropriate parameters. The rule is that if you implement an interface, you must BELL_C16.QXD 1/30/05 4:24 PM Page 227 . javax.swing.*; java.awt, java.awt.event and javax.swing are the names of packages. Each of these packages contains a number of useful classes. For example, the class JButton is in the package. similar to packages. We will now see how packages are used within a programming language. Java programs typically start with import statements, such as: import java.awt.*; import java.awt.event.*; import. exception and threads java.util these are useful utility classes, such as Random and ArrayList java.io text input and output streams for characters and numbers java.net classes that carry out