4.3. Key abstractions and mechanisms

Lecture



Key abstractions

Finding and choosing key abstractions. A key abstraction is a class or object that is part of the vocabulary of the problem domain. The most important value of key abstractions lies in the fact that they define the boundaries of our problem: they single out what belongs to our system and is therefore important to us, and eliminate what is superfluous. The task of singling out such abstractions is specific to the problem domain. As Goldberg asserts, "the correct choice of objects depends on the purpose of the application and on the degree of detail of the information being processed" [51].

As we have already noted, determining key abstractions involves two processes: discovery and invention. We discover abstractions by listening to specialists in the problem domain: if an expert talks about it, then this abstraction is usually genuinely important [52]. By inventing, we create new classes and objects that are not necessarily part of the problem domain, but are useful in designing or implementing the system. For example, the user of an automated teller machine says "account, withdraw, deposit"; these terms are part of the vocabulary of the problem domain. The developer of the system uses them, but adds his own, such as database, screen manager, list, queue and so on. These key abstractions are created not by the problem domain but by the design.

The most powerful way of singling out key abstractions is to reduce the problem to already known classes and objects. As will be shown below in Chapter 6, in the absence of such reusable abstractions we recommend using scenarios to drive the process of identifying classes and objects.

Refining key abstractions. Having determined the candidates for the roles of key abstractions, we must evaluate them by the criteria described in the previous chapters. In Stroustrup's words, "the programmer must ask himself: How are objects of the class created? How can objects of this class be copied and/or destroyed? What operations can be performed on this object? If the answers to these questions are hazy, then the overall conception is probably unclear, and it is better to sit down and think again than to rush into programming" [53].

Having determined new abstractions, we must find their place in the context of the already existing classes and objects. One should not try to do this strictly top-down or bottom-up. Halbert and O'Brien maintain that "there is no particular need to build a class hierarchy starting from the topmost class and then supplementing it with subclasses. More often you create several independent hierarchies, recognize their common features and factor out one or several superclasses. Several passes up and down the hierarchy are required to create a software design" [54]. This is not a carte blanche for hacking, but merely an observation based on experience that confirms the fact that object-oriented design is a process of successive approximations. Stroustrup makes a similar observation: "The most frequent reorganizations in a class hierarchy are merging the coinciding parts of two classes into one and splitting a class into two new ones" [55].

4.3. Key abstractions and mechanisms

Classes and objects must be at the proper level of abstraction: not too high and not too low.

It is difficult to place classes and objects at the right levels of abstraction straight away. Sometimes, having found an important class, we can move it up in the class hierarchy, thereby increasing the degree of code reuse. This is called class promotion [56]. Similarly, we may come to the conclusion that a class is too generalized, and this makes inheritance difficult: a semantic gap or a granularity conflict occurs [57]. In both cases we try to detect coupling or insufficient cohesion of abstractions and to mitigate the conflict.

Programmers often treat the proper naming of classes and objects lightly, but in fact it is very important to reflect in the designation of classes and objects the essence of the things they describe. Programs must be written carefully, like works of literature, thinking both of the readers and of the computer [58]. In identifying a single object alone you need to invent names: for it, for its class and for the module in which the class is declared. Multiply by a thousand objects and hundreds of classes, and you will understand how acute the problem is.

We propose the following rules:

  • Objects should be named with nouns: theSensor or shape.
  • Classes should be named with generalized nouns: Sensors, Shapes.
  • Modifier operations should be named with active verbs: Draw, moveLeft.
  • The names of selector operations should include a query or a form of the verb "to be": extentOf, isOpen.
  • Underscores and the use of capital letters are at your discretion; just try not to contradict yourself.

Identifying mechanisms

How do we find mechanisms? In the preceding discussion we called mechanisms the structures by means of which objects interact with one another and behave as required. Just as designing a class in fact defines the behavior of individual objects, so mechanisms serve to specify the behavior of a collection of objects. Thus mechanisms represent patterns of behavior.

Consider a requirement placed on an automobile: pressing the accelerator must lead to an increase in engine revolutions, and releasing the accelerator to a decrease. How this happens is a matter of complete indifference to the driver. Any mechanism that provides the required behavior may be used, and its choice is a matter of the designer's taste. For example, any of the engineering solutions proposed below is admissible:

  • A mechanical linkage between the accelerator and the carburetor (the usual solution).
  • A pressure sensor is placed under the pedal and connected to a computer that controls the carburetor (a drive-by-wire mechanism).
  • There is no carburetor. The fuel tank is located on the roof of the automobile and the fuel flows freely into the engine. The fuel flow is regulated by a clamp on the tube. Pressing the accelerator pedal loosens the clamp (very cheap).

Which implementation exactly the designer chooses depends on such parameters as cost, reliability, manufacturability and so on.

Just as it would be an inadmissible discourtesy on the part of a client to violate the rules for using a server, so too going beyond the rules and constraints on behavior specified by a mechanism is socially unacceptable. A driver would be surprised if, on pressing the accelerator pedal, he saw the headlights come on.

Key abstractions define the vocabulary of the problem domain; mechanisms define the essence of the design. In the process of design the developer must invent not only the innards of classes, but also how the objects of these classes will interact with one another. But a concrete mechanism of interaction will still have to be decomposed into methods of classes. In the end the protocol of a class will reflect the behavior of its objects and the workings of the mechanisms in which they participate.

Mechanisms, then, represent strategic decisions in design, like the design of the class structure. On the other hand, designing the interface of some single class is rather a tactical decision. Strategic decisions must be made explicitly, otherwise we shall end up with a disorganized crowd of objects rushing to do the work, shoving one another aside. The most elegant, well-proportioned and fast programs embody carefully worked-out mechanisms.

4.3. Key abstractions and mechanisms

Mechanisms are the means by which objects interact with one another to achieve the required higher-level behavior.

Mechanisms represent only one of the patterns that we find in structured systems. Thus, at the lower end of a peculiar biological pyramid are idioms. These are turns of expression specific to programming languages or programming cultures, reflecting generally accepted ways of expressing oneself [The defining characteristic of an idiom is that ignoring or violating it entails immediate social consequences: you turn into a yahoo or, worse still, into an outsider undeserving of respect]. For example, in CLOS it is not customary to use underscores in the names of functions or variables, although in Ada this is a common thing [59]. In learning a language one has to learn its idioms, which are usually handed down in the form of folklore. However, as Coplien noted, idioms play an important role in codifying low-level patterns. He observed that "many common programming activities are idiomatic" and that recognizing such idioms therefore makes it possible "to use C++ constructs to express functionality outside the language itself while preserving the illusion that they are part of the language" [60].

The place at the top of the pyramid is occupied by frameworks. A framework is a collection of classes intended for a particular application situation. A framework provides ready-made classes, mechanisms and services that can be used immediately or adapted to one's own needs.

If idioms make up part of the programming culture, then frameworks are usually a commercial product. For example, Apple MacApp and its successor Bedrock are frameworks written in C++ and intended for building applications with the standard Macintosh user interface. An analogous role for Windows is played by the Microsoft Foundation Classes and Borland Corporation's ObjectWindows.

Examples of mechanisms. Consider the drawing mechanism usually employed in graphical user interfaces. In order to present some picture on the screen, several objects are needed: a window, a view, the model that is to be shown, and finally the client, which knows when the model must be drawn but does not know how to do it. First the client gives the window the command to draw itself. Since a window may include a number of views, it in turn orders each of them to draw itself. Each view sends a message to its model to draw itself, as a result of which the image appears on the screen. In this mechanism the model is completely separated from the window and the view in which it is presented: views can send messages to models, but models cannot send messages to views. Smalltalk uses a variant of this mechanism called the Model-View-Controller paradigm (MVC) [61].

Mechanisms, then, represent a level of reuse in design higher than the reuse of individual classes. MVC, for example, is the basis of the user interface in the Smalltalk language. This paradigm in turn is built upon the dependency mechanism, which is embedded in the behavior of the base class of the Smalltalk language (the class object) and is often used by the Smalltalk class library.

Examples of mechanisms can be found in many systems. The structure of an operating system, for example, can be described at a high level of abstraction by the mechanisms that are used for scheduling programs. A system may be monolithic (like MS-DOS), have a kernel (UNIX) or represent a hierarchy of processes (the THE operating system) [62]. Artificial intelligence systems use a variety of decision-making mechanisms. One of the most widespread is the blackboard mechanism, into which each individual source of knowledge independently enters its information. In such a mechanism there is no central control, but any change in the blackboard may serve as the impetus for the system to work out a new way of solving the posed problem [63]. Coad similarly identified a number of common mechanisms in object-oriented systems, including patterns of time association, event logging and broadcast message distribution [64]. In all cases these mechanisms manifest themselves not as individual classes but as structures of collaborating classes.

This concludes our study of classification and of the concepts that form the basis of object-oriented design. The next three chapters are devoted to the method itself, in particular to the notation, the design process and the examination of practical examples.

Conclusions

  • Identifying classes and objects is the most important task of object-oriented design; the process of identification consists of discovery and invention.
  • Classification is the problem of grouping (clustering) objects.
  • Classification is a process of successive approximations; the difficulties of classification are due mainly to the fact that there are many equally valid solutions.
  • There are three approaches to classification: classical categorization (classification by properties), conceptual clustering (classification by concepts) and prototype theory (classification by similarity to a prototype).
  • The scenario method is a powerful tool of object-oriented analysis; it can be used with other methods as well: classical analysis, behavior analysis and domain analysis.
  • Key abstractions reflect the vocabulary of the problem domain; they are either found within it or invented in the process of design.
  • Mechanisms denote strategic design decisions concerning the joint activity of objects of many different types.
created: 2020-12-19
updated: 2026-03-10
144



Was this answer useful?
Choose a quick rating so we can improve the next answer for you.
How satisfied are you?


Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Object Oriented Analysis and Design"

Terms: Object Oriented Analysis and Design