Introduction to Object-oriented Programming |
A complete PDF version of the text book is now available. The PDF version is an almost complete subset of the HTML version (where only a few, long program listings have been removed). See here. |
In this and the following chapter we will gradually unveil important theoretical and conceptual aspects of object-oriented programming. After this, in Chapter 4 we will be more concrete and practical, again in terms of the Hangman example.
In this chapter we will deal with a number of different aspects that lead in the direction of object-oriented programming. We do not attempt to relate these aspects to each other. Thus, in this chapter you will encounter a number of fragmented observations that - both individually and together - bring us towards object-oriented programming.
|
2.1. Client, Servers, and Messages
Contents Up Previous Next Slide Annotated slide Aggregated slides Subject index Program index Exercise index
We will start with message passing in between objects. One object (often called the client) sends a message to another object (often called the server). The client asks for a service. The server will do the job, and eventually return an answer to the client.
"Client" and "server" are general role names of objects. When the server receives a message, it may decide to forward the message to some subserver (because it cannot handle the request - solve the problem - itself). In this way, the server becomes a client of another server.
We will primarily be concerned with message passing where the client waits for an answer from the server. Thus, nothing happens in the client before the server has completed its work. This is referred to as synchronous message passing. Asynchronous message passing is also possible. This involves parallel activities. This is a slightly more advanced topic.
Peter orders a Pizza at AAU Pizza by email. Via interaction between a number of service providers, a pizza is delivered to Peters group room |
Below we study an everyday example of message passing between an object (person) who orders a pizza, and a "Pizza server". The Pizza server relies on other subservers (subcontractors), in our example the butcher, the greengrocer, and a transport service. Thus, the Pizza crew are customers in other shops, and they make use of other services.
Notice that Peter - the hungry guy - is not aware of the subcontractors. Peter only cares about the interface of the Pizza server.
In some versions of this material you may interactively play the Pizza scenario in order to find out how the objects cooperate when Peter orders a Pizza. The scenario emphasizes that there is always a single current object (at least as long as we deal with synchronous message passing).
Figure 2.1 The scenario of pizza ordering. The scenario focuses on a number of objects (persons) who communicate by message passing. |
Is it reasonable that Peter is idle in the period of time in between pizza ordering and pizza delivery? It depends on the circumstances. If you wait in the restaurant you may actually be left with feeling of 'just waiting'. If Peter orders the Pizza from his group room, Peter probably prefers to send an asynchronous message. In that way he can do some work before the pizza arrives. In this mode, we should, however, be able to handle the interrupt in terms of the actual pizza delivery. Again, this is a more advanced topic.
A client asks for a service at some given service provider (server ). This may lead the service provider (which now plays a client role) to ask for subservices Clients and servers communicate by passing messages that return results Try the accompanying SVG animation |
In our model of message passing, it is inherent that messages return a result. Alternatively, we could use a model in which the 'the message result' is handled by a message in the other direction. We have chosen a model, which can be used directly in mainstream object-oriented programming languages (such as C#).
We will come back to clients and servers in the context of the lecture about classes, see Section 10.2. Message passing is taken up in that lecture, see Section 10.3.
2.2. Responsibilities
Contents Up Previous Next Slide Annotated slide Aggregated slides Subject index Program index Exercise index
Responsibility - and distribution of responsibility - is important in a network of cooperating objects. In Section 2.1 we studied a network of people and pizza makers. The Pizza maker has certain assumptions about orders from customers. We cannot expect the pizza maker to respond to an order where the customers want to buy a car, or a pet. On the other hand, the customer will be unhappy if he or she receives spaghetti (or a chocolate bar) after having ordered a pizza calzone.
Objects that act as servers manage a certain amount of responsibility |
We will talk about the responsibility of an object as such. The object is responsible to keep the data, which it encapsulates, in good shape. It should not be possible to bring the object in an inconsistent state.
The responsibility of an operation of a class/object does also make good sense. If the sender of the message, which activates an operation fulfills certain (pre)conditions, it is the obligation of the operation to deliver a result which comply with a certain (post)condition.
The responsibilities of an object, together with the responsibilities of the operations of the object, sharpen the profile of the object, and they provide for a higher degree of cohesion of the object.
|
In Chapter 49 through Chapter 53 we will devote an entire lecture to discussion of responsibilities, and how to specify the distribution of responsibilities among objects. This will involve contracts, which (again) is a real-world concept - a metaphor - from which can we can gain useful inspiration when we develop software.
You should care about the responsibilities of both objects and operations The distribution of responsibilities will become a major theme later in the course |
2.3. Data-centered modularity
Contents Up Previous Next Slide Annotated slide Aggregated slides Subject index Program index Exercise index
Message passing is mainly a dynamic (run-time) aspect of object-oriented programs. Let us now focus on a static aspect: modularity.
|
Non-modular programs (programs written without decomposition) are unwieldy. The question we care about here is the kind of modularity to use together with abstract data types. We will identify the following kinds of modularity:
|
Procedural modularity is used in structured programming, e.g. in C programs. It covers both functions and procedures. Procedural modularity remains to be very important, independent of programming paradigm!
Boxing modularity (our name of the concept) captures the module concept known from, e.g. Ada [Ada80] and Modula-2 [Wirth83]. In C, there are only few means to deal with boxing modularity. Most C programmers use the source files for boxing.
Boxing modularity allows us to box a data type and the operations that belong to the type in a module. When using data centered modularity the module becomes a type itself. This is an important observation. Object-oriented programming is based on data centered modularity.
Object-oriented programming is based on data-centered modularity |
2.4. Reusability
Contents Up Previous Next Slide Annotated slide Aggregated slides Subject index Program index Exercise index
Let us now, for a moment, discuss reusability. The idea is that we wish to promote a programming style that allows us to use pieces of programs that we, or others, have already written, tested, and documented. Procedure libraries are well-known. Object-oriented programming brings us one step further, in the direction of class libraries. Class libraries can - to some degree - be thought of as reusable abstract data types.
More reuse - Less software to manage |
We identity the following reusability challenges:
|
Finding has been eased a lot the last decade, due to the emergence of powerful search machines (servers!). Understanding is still a solid challenge. Documentation of reusable parts is important. Tools like JavaDoc (developed as on-line resources by Sun as part of the Java effort) are crucial. We will study interface documentation of class libraries later in this material. Modification should be used with great care. It is not a good idea to find a procedure or a class on the Internet, and rewrite it to fit your own needs. When the next version of the program is released you will be in great trouble. A modular modification approach, which separates your contributions from the original contributions, is needed. In object-oriented programming, inheritance alleviates this problem. The actual integration is relatively well-supported in modern object-oriented programming languages, because in these languages we have powerful means to deal with conflicts (such as name clashes) in between reused components and our own parts of the program.
2.5. Action on objects
Contents Up Previous Next Slide Annotated slide Aggregated slides Subject index Program index Exercise index
The final aspect that we want to bring up in our road towards object-oriented programming is the idea of action on objects. Actions should always be targeted at some object. Actions should not appear 'just up in the air'. Bertrand Meyer [Meyer88] has most likely been inspired by a famous John F. Kennedy quote when he formulated the idea in the following way:
Ask not what the system does: Ask what it does it to! [Bertrand Meyer] |
|
The activation of a concrete procedure or function is typically more complex than in ordinary imperative programming. The message is sent to an object. The reception of the message may cause the object to search for the best suited operation (method) to handle the request by the message. This process is sometimes called method lookup. In some object-oriented language the method lookup process is rather complicated.
In the next section we continue our road towards object-oriented programming, by discussing concepts and phenomena.
2.6. References