Static Relationships


There are an open -ended number of possible relationships among objects. Some are so common as to have special notation invented for them in modeling tools (UML, for example): using , is-a-part-of , is-a- kind-of , and contains are examples of common relationships.

From this large set of possible relationships, only two tell us anything about the intrinsic nature of our objects. All of the others provide information about the context ”the application ”in which our objects operate ; they are situational relationships . The two relationships that describe intrinsic aspects of objects are is-a-kind-of and collaborates-with .

Is-a-Kind-of Relationship

Classes are not essential to object thinking, merely a convenience. From a cognitive standpoint, the use of classes allows us to think about an entire group instead of all the members of that group ”something we have been doing throughout this book.

Combining the idea of classes with the is-a-kind-of relationship yields a taxonomy, a particular kind of structural organization, that can then be used as a kind of index to help in finding an object with a particular set of behaviors. Figure 9-1 is a class hierarchy diagram ” specifically , a taxonomy of the classes in the mortgage trust example introduced in Chapter 7.

click to expand
Figure 9-1: The is-a-kind-of relationships among the objects (via their classes) in the mortgage trust example.

Using a taxonomy requires only a general notion of the behavior or behaviors you need in an object as a starting point. You can find an object with that (or some of those) behaviors and then move up or down the taxonomy to find an object that matches your needs in a more precise manner. If no existing class of objects meets your needs, you can still use the taxonomy to simplify your creative work by finding the object that best matches your needs and saying that your new object is-a-kind-of the one you found. You then create a subclass and give it the precise behavior you want, and you use, via inheritance, behaviors that already exist in the superclass.

From a cognitive point of view (we will discuss an alternative point of view in just a minute), your taxonomy must follow two rules:

  • Exhibit a single line of descent (single inheritance) based on nothing but the behaviors of the objects. Ideally, you should create your taxonomy (class hierarchy) as soon as you have completed side 1 of the object cube. That way, you are not tempted to create a hierarchy based on object internals, that is, methods or instance variables . Single inheritance is important to avoid abominations that break the taxonomy ”the way the platypus breaks the Linnaean taxonomy of fauna. (Linnaeus noted certain attributes of animal species such as warm blooded, lays eggs, live birth, and covered with hair and used them as the basis for classifying fauna. The platypus , a furry mammal that lays eggs, breaks the classification rules and is therefore an abomination. )

  • Subclass only by extension ”by adding behaviors. A subclass should be able to do everything its superclass (or superclasses) can do, plus at least one more thing. This means that you can substitute an object from a subclass in any situation calling for an object from its superclass and still get the behavior you expect. If you define a subclass by subtraction (taking away a behavior) or by redefinition (overriding a behavior), you create cognitive dissonance. [1] Users of your taxonomy can never be entirely sure of the behavior they will get from classes without looking inside those classes to see what they really do. This is, of course, an egregious violation of encapsulation.

Class hierarchies can be viewed from an implementation perspective as well as a cognitive perspective. Unfortunately, these two perspectives are not always in concert. When they disagree , it is almost always because the hierarchy is perverted to conform to constraints imposed by a nonobject machine or virtual machine (programming language).

In Chapter 5, Vocabulary: Words to Think With, it was noted that one aspect of a class was to act as a repository for code and information shared by all instances (objects) of that class. In terms of efficiency, this is a good idea because storage space is minimized and changes can be made in a single place. It becomes very tempting, however, to use this fact to justify creating your class hierarchy based on shared code instead of shared behaviors. A similar error arises from treating object variables (instance variables) as if they were data attributes and then creating your hierarchy based on shared attributes. Always create hierarchies based on shared behaviors, side 1 of the object cube, only.

Collaborates-with Relationship

Collaborations arise if, and only if, object A must use a service from object B during the interval defined by object A receiving a message (request for service) and object A returning the appropriate result object to the sender of the message to object A. All collaborations are synchronous in the sense that object A must invoke and wait for results from object B before it can complete whatever work is required in response to the message it received.

Collaborations are almost always hard coded: they require manifest references in the algorithm of the method where the collaboration occurs. Because of the hard-coded nature of collaborations, we assert that they define part of the intrinsic nature of an object. In every circumstance, in every context, the collaboration will occur if object A receives the indicated message.

Collaborating objects are very tightly coupled . For this reason, collaborations should occur inside the encapsulation barrier, with objects occupying instance variables, objects being received along with messages, and objects occupying temporary variables. Collaborations with objects occupying global variables are good or bad depending on the justification of need for a global variable. Collaborations outside the encapsulation barrier are sometimes necessary but should be avoided (by refactoring the distribution of responsibilities among objects) whenever possible.

Wirfs-Brock introduced a dedicated model ”a collaboration graph ”that was seldom adopted by actual developers. Figure 9-2 shows an example of such a graph. The graph depended on the use of contracts (side 3 of the object cube) to define potential connection points for potential collaborations. Deciphering the graph was difficult because of line tracing from client to server. Collaboration graphs (probably unintentionally) provide a visual metaphor consistent with the object = software integrated circuit introduced by Brad Cox. Interesting collaboration graphs look like circuit boards when viewed as a gestalt.

click to expand
Figure 9-2: A visual model of collaborations, based on a graph in Designing Object Oriented Software, by Wirfs-Brock et al., 1991.

Situational Relationship

Collaborations are not the only example of uses relationships among objects. It can be said that object A uses object B if object B has asynchronously provided information or services to object A that object A finds useful for its own work. For example, an airplane has a responsibility to identify itself, which requires an id object, which leads to the assumption that at some point in the past the airplane asked some national naming authority for an id object. That request for an id object is an example of a uses relationship between the airplane and namingAuthority . (It is not a collaboration because the airplane does not interact with namingAuthority each time it receives the id request.)

Except for collaborations, the fact that particular objects use the services of others reflects the demands of the application (the situation) and not intrinsic needs of the objects themselves . The same thing can be said of the particular objects that are aggregated into components : the aggregation is a reflection of the demands of a particular circumstance, nothing more. This is not to say that it is unimportant to understand (and probably model) situational relationships, but it is important to recognize, and keep in mind, that you are not modeling the intrinsic nature of any objects.

What then do you need to understand about a situational relationship application?

  • The objects that are participating in the work of the application

  • The objects that have a need to communicate with others and the general nature of that communication

  • The data ”really, the collective memory of objects involved in the application; any relationships among data items

  • An overview, or gestalt, view of the application and its participants

The following sections describe models that might be helpful as a guide to thinking about a situational relationship application.

Static Relationship Model

A static relationship model (the UML equivalent is a class relation diagram or an object relation diagram) can provide all of this information. Static relationship models (SRMs) are models of applications and not domains. They are called static because the information portrayed in this type of model is supposedly invariant. It must constantly be remembered that invariant applies to the time and space boundary defined by each individual application; the relationships might or might not exist in any other application. This is a major point of difference with data-driven approaches to modeling objects.

A data-driven approach assumes that objects are equivalent to data entities. Data entities are expected to be defined at the level of the domain because it is assumed that they are the basis for creating a database that will be common to all applications. This is one more example of perpetuating the traditional view of software as data structures plus algorithms. A data-driven approach to objects posits a singular database containing all of the data structures and allows multiple applications ”application is equal to algorithms only ”to share a common data structure.

Note  

Data modeling and object modeling are so dissimilar that a named concept, the impedance mismatch problem , was coined to reflect the difficulty of integrating object and database applications. Some of the problems were simply technical and have been more or less resolved. The inability of classical databases to generate changed events or otherwise notify objects of a need to update themselves when a cell in a database table has been altered is one example. The basic difference, however, arises from the fact that objects are domain-centric models, while schemas are machine/database models. The effort required to normalize a conceptual data model into a logical data model (one capable of implementation in a database) essentially has to be reproduced in some degree each time an object application wants to interact with a database ”usually for persistence. Immense amounts of effort have gone into the development of middleware that allows objects and databases to interact with each other.

An SRM, from an object thinking point of view, is a gestalt view of the objects participating in an application (cast of characters ) and relationships that exist among those objects when in that application. Relationships most frequently denote potential interactions among objects, just as a roadmap shows potential travel [2] among cities connected by those roads . Relationships might also denote constraints on object behaviors or associations while the objects in question are participating in a given application.

Most application SRM diagrams are little more than semantic nets (see Chapter 6) with more precision, more detail, and an aura of specification instead of discovery. A semantic net also identifies the cast of characters ”objects ”in a domain and reveals relationships among those objects. Semantic nets were used as a heuristic starting point for object discovery. SRMs are intended as a kind of specification: information to guide the developer in the creation of the application.

Most of the information depicted in a semantic net will be used to define and create objects. Some of that information will be used to define applications, especially constraint-or rule-based information on the semantic net. Consider the mortgage trust example discussed in previous chapters. Figure 9-3 shows a fragment of the semantic net dealing with relationships between the price of a home and the median price of homes in a neighborhood. The semantic net fragment shows a specific business rule: the home price must be less than or equal to the median price of homes in the neighborhood. This rule is not a domain rule; it is an application rule. It should not become a basis for defining the home, neighborhood, or price (actually money) objects because it does not reveal the intrinsic nature of any object. Instead, it shows a relationship that exists only in one or more applications (contexts), perhaps the collect and validate loan application data application.

click to expand
Figure 9-3: A semantic net fragment, showing a constraining relationship among objects in a domain.

Figure 9-4 shows an SRM for the mortgage trust example. Notice that it is very similar to the semantic net: most of the same players are still present, and most of the links among them are still evident as well. It differs from the semantic net in the use of implementation names for many of the objects (classes), it shows some of the interesting details of object construction (instance variables and method names ), and it uses terminology more suitable for implementation than discovery. (Technical rather than domain jargon is allowed on an SRM but not on a semantic net.)

click to expand
Figure 9-4: SRM depiction of the classes and relationship in the mortgage trust example.

Collective Memory Map

One of the important responsibilities that an object might assume is to portray and maintain some specific bit of information (data). Examples include numbers, integers, floating-point numbers , dates, times, characters, strings, and money. None of these objects limit themselves strictly to the portrayal and maintenance of information; they also have other interesting behaviors appropriate for the kind of information they maintain. Dates, for example, can perform calendar- related calculations and comparisons. Numbers can do arithmetic. Strings have many behaviors similar to those of collections: iteration, insertion, deletion, and arrangement, for example.

Given their specialized nature, data depiction objects frequently are found occupying instance variables of other objects. An airplane object, for example, has an instance variable named id , which is occupied by a string object.

Given the information-centric nature of the contemporary world, numerous constraints and relationships exist between and among data depiction objects. Although it is possible to capture this type of relationship in a standard SRM, doing so obscures, somewhat, the real nature of the relationship. Suppose, for example:

  • An airplane object has instance variables for id , containing a serial number such as N543UE; transponderCode , a four-digit integer; and status , containing a character whose value indicates that the airplane is in normal operation, hijacked, in a declared emergency, or in controlled airspace.

  • An airspace object has an instance variable, assignedAircraft , that contains a collection of blips .

  • A blip object has instance variables for id , transponderCode , altitude , latitude , longitude , vector , priority , and status .

Figure 9-5 shows a fragment of an SRM that relates the three objects under discussion. This fragment obscures a great deal of detail about the actual relationships involved ”for example, the following rules:

  • Transponder code value must equal 1200 for VFR flight.

  • Transponder code value must equal 7500 if plane has been hijacked.

  • Transponder code value must equal 7700 if plane is in a state of emergency.

  • Transponder code value must equal 7600 if plane has lost communications.

  • Transponder code must equal value specified by ATC for its blip representation.

  • Transponder code value must be consistent with airplane s status value.

  • Blip ID and airplane ID must be consistent.

  • Blip priority must be 1A if transponder code is 7500, 7600, or 7700.

    click to expand
    Figure 9-5: Relationships among airplane, blip, and airspace.

It would be possible to model all of these constraints simply by adding relationship symbols between blip and airplane on the SRM ”if you are willing to sacrifice a great deal of readability. Alternatively, since all of these relationships are among objects occupying instance variables of other objects, there is value in modeling them directly in a separate model, a collective memory map like that depicted in Figure 9-6.

click to expand
Figure 9-6: Relationships among objects occupying instance variables of other objects in the airplane, blip, and airspace example.

A collective memory map (CMM) is another type of static diagram constructed according to the following rules:

  • Objects appearing on a CMM are occupants of instance variables in other objects.

  • Objects appearing on a CMM must have a primary role of data depiction and maintenance (maintenance implies self-validation, self-persistence, and self-based access control); they can be considered primitives in the same sense that a database defines certain objects as primitives. Most often these include numbers, characters, strings, dates, money, time, and similar objects.

  • A kind of collection that is restricted to containing primitive objects, called a ValueHolder , can also be depicted in a CMM.

  • Each object depicted is named using dot notation that identifies the container object name and instance variable name ”for example, customer.lastName .

  • In those cases in which the instance variable contains a ValueHolder instead of a primitive, the dot notation is extended to include the label (key) associated with the actual primitive ”for example, customer.description.gender .

  • Relationships among objects on the CMM are drawn as connecting lines with appropriate labels.

Figure 9-7 depicts a collective memory map for the mortgage trust example. Collective memory maps are situational: they reflect constraints that exist among data objects in the context of a particular application. In some cases, it might be useful to create a domain-level version of a collective memory map. A domain-level collective memory map would have some things in common with an enterprise memory model, namely a global depiction of all the data in the domain and the objects in which it might be found and any relationships among those objects that were truly invariant across the domain. If your enterprise is interested in constructing such a global model, you need to remember some important caveats:

  • Object thinking presumes that data objects represent information or knowledge that objects need to perform their assigned tasks , while enterprise data models presume to depict all the data that the system must remember about objects. This is a critical distinction.

  • The global model should contain only relationships and constraints that are invariant across the domain.

  • A CMM for an application can add, delete, and modify relationships to reflect the situational context. If there is a conflict, the global map must be modified.

    click to expand
    Figure 9-7: A collective memory map for the mortgage trust example.

Architecture

Almost all applications have an overarching structure or means of organization, which might be called architecture . Architecture affects the way you think about implementation, especially when the architectural pattern is so common as to be assumed. For example, traditional structured development presumed a hierarchical command-and-control architecture as reflected in a program structure chart (Figure 9-8). This visual pattern is seen in the mainline-plus-subroutines source code organization scheme (Figure 9-9). The hierarchical control architecture is a codification and expression of a lot of ideas about good program design, ideas that support most of the rest of structured development approaches.

click to expand
Figure 9-8: The proper organization (architecture) of a program consistent with structured development ideas.

Figure 9-9: A structure depicting how actual source code might reflect the hierarchical control architecture.

A prototypical architecture that reflects object thinking ideals and principles also exists: model-view-controller (MVC). MVC is not a mandated architecture. You can use almost any of the commonly encountered architectural patterns (see the sidebar Architectural Patterns and Objects ), but an investigation of MVC is instructive and important for the way it illustrates and reinforces the other aspects of object thinking that have been discussed in previous chapters.

start sidebar
Architectural Patterns and Objects

MVC is but one of a number of architectural patterns or prototypical ways of organizing a group of objects engaged in a collective task. Commonly encountered alternative architectural patterns include hierarchical control, pipes and filters, client/server, and several variations of the blackboard architecture. With the exception of hierarchical control (the antithesis of object ideals), all of these alternative architectures can be consistent with the principles of object thinking.

Regarding pipes and filters , readers familiar with UNIX/Linux will immediately recognize this pattern. Two kinds of objects are involved: pipes, which are connectors and possibly temporary storage locations; and filters, which are places where specialized services (transformations) are performed. Figure 9-10 illustrates a small pipes-and-filters architecture.

click to expand
Figure 9-10: Objects move along the route provided by the pipes and obtain services from the objects embodying the filters.

Traditional thought about pipes-and-filters architecture reflects traditional thinking about the separation of data and process. From that nonobject point of view, data passes along the pipes ( pushed or pulled by the connected filters) and is manipulated by processes at each filter station.

Simply reversing the idea about who is in charge and assuming that everything is an object makes this a perfectly acceptable architecture for use by object thinkers. The architecture merely provides transport objects (pipes) and service providing objects (filters). A large pool of objects requiring a similar set of services can ask the pipes for transport to the filters whose services they need, take advantage of both, and effect self-processing in a very efficient manner.

Client/server architectures are the mainstay of the networked business world. Two-tier client/server systems are almost identical with MVC, with the model (usually a database) physically located on a server and most of the view and control aspects on clients . Conversely, MVC can be seen as simply an n- tier (or peer-to-peer) client/server architecture. Object thinking will frequently, and naturally, lead to the construction of a client/server architecture, the only difference being the overall distribution of responsibilities and the absence of overt controller, manager, and scheduler objects.

Blackboard architectures actually come in at least three variations, which I ll label bulletin boards, blackboards , and whiteboards . All variants have common elements as illustrated in Figure 9-11: service providers, requesters, a common communication space, requests for service, and results. Each of these elements is, of course, an object.

click to expand
Figure 9-11: Elements common to all blackboard systems.

In the simplest form of blackboard architecture, the bulletin board , requesters post requests in the common space, and service providers constantly poll that space looking for requests they might service. Upon finding an appropriate request, the service provider retrieves it and provides appropriate satisfaction, a result, which is then returned to the common space, where the original requester finds it (constantly polling the space ” Are you there yet? ) and retrieves it.

Request and result objects are relatively straightforward containers ”of the information necessary to specify a result and the result that can be queried by the requester upon retrieval of the information. A ride board, such as that found in most university student unions, is a prototypical example of a bulletin board system.

Give the common space some interesting responsibilities, and you have a blackboard variant. The common space maintains a list of service providers to which it can match a posted request. When a match is found, the request is forwarded appropriately. The common space also retains a list of requesters and their requests so that when a result is posted it can forward the result to the appropriate requester. Care must be taken not to turn these responsibilities into a command-and-control structure.

Whiteboards are similar to the tuple spaces proposed by David Gelernter [3] and implemented in his Linda programming language. In this variant, the shared location ”the whiteboard ”is called tuple space and the request and result objects are called tuples . Tuples can actually perform work, transform themselves by combining with and interacting with other tuples, in tuple space. The tuple space itself is also given enhanced responsibilities for filtering and feeding forward (to the next hierarchical level of tuple spaces) its contents (tuples).

All of these architectures are perfectly consistent with the ideals of object thinking as long as the assumptions about control, distribution of responsibility (factoring), and object autonomy illustrated in MVC are respected.

end sidebar
 

Figure 9-12 depicts the model-view-controller architecture. The figure is actually a slight variant of the architecture proposed as the Smalltalk language and development environment was being created at Xerox PARC. MVC is almost always discussed in the context of a graphical user interface environment ”invented simultaneously with Smalltalk ”but the important principles behind the architecture are not limited to such an environment.

click to expand
Figure 9-12: Generalized model of the MVC concepts.

MVC is grounded in the idea of specialization and distribution of responsibilities ”specifically, the identification of three main categories of responsibility (presentation or visualization, computational work, and coordinating communications) and assigning those to different sets of objects.

The model comprises those objects actually engaged in accomplishing the work objectives of the application. Model objects have a need to communicate with one another by sending messages and by notifying other objects of internal state changes. In Figure 9-12, model objects are depicted as round circles.

One of the model objects assumes the role of the application object . The application object assumes responsibility for startup and shutdown activities in collaboration with the other model objects and acts as a kind of global (within the application) repository of objects and information that need to be visible to other model objects while the application is running.

The view consists of a hierarchically organized collection of objects ”for example, widgets, windows , and icons ”whose primary task is creating visualizations of objects so as to be comprehensible to human beings. This definition presumes a GUI environment and reflects the history that shaped the original MVC architecture.

A view object does not have to be a GUI element. If an object creates a representation of itself other than its native implementation, that too would be a view object. Examples of nonsensory views would include bit stream serializations that allow objects to exist in a relational database or an XML statement that allows an object to be shared across applications and implementation languages.

In Figure 9-12, view objects are depicted as rounded rectangles. The hierarchical organization of views reflects the fact that simple objects have simple views and more complicated objects have views that are collections of the views of the simpler objects that they comprise. It s also possible for any object to possess multiple views of itself. An integer, for example, might have a simple bitmap view that depicts the value of the integer, and it might have an update view consisting of a widget depiction (rectangular entry field area) plus the bitmap of its value. Figure 9-13a illustrates the hierarchical composition of a complex view, and Figure 9-13b provides an example using the mortgage application.

click to expand
Figure 9-13a: Hierarchical composition of a complex view.
click to expand
Figure 9-13b: The application completion screen in the mortgage trust example is a hierarchically organized collection of object views.

The controller is badly misnamed. Control in the classical programming sense is anathema to object thinkers and right-thinking autonomous objects everywhere. I ll substitute the word coordinator for the rest of this discussion. Coordination refers to the tasks involved that allow one object to send a message to another and for an object to notify any interested object of a state change in itself.

Ensuring that it s possible for two objects to exchange messages is a matter of visibility: the objects have to be able to see one another. An example of coordinating visibility is the application object having a variable that contains a collection of all the objects participating in the application. Should one object need to talk to another, it can ask the collection for an object by name or by criterion. Similarly, the application object might have a variable that will contain the currently active or currently selected object, to which other objects might need to send messages. Because the application object is global within the application, all other objects can send messages either to it or to the objects occupying its instance variables.

Event (state change) notification was the main responsibility of historic controller objects, another manifestation of the GUI-centric history of MVC. We will use a special-purpose object, an eventDispatcher , to provide all the necessary coordination associated with event notification. Dispatchers were introduced earlier; the following paragraphs will serve as a reminder.

An eventDispatcher is a simple two-dimensional table, the first column of which contains a list of events that can be dispatched and the second column of which contains a collection (possibly an ordered collection) of notificationRequest objects.

A notification request is a dyad consisting of the name/ID of the object requesting notification of an event s occurrence and a message to be sent to that object as means of notification. If the notification collection is ordered (for priority, for instance), the notification request can be a triad of name, message, and priority number.

An eventDispatcher can add or delete events, must accept and delete registrations on request, and, when an event is detected , must tell each registration in the associated queue to execute itself (send the contained message to the contained object reference).

If the registrationQueue is an ordered collection, it must reorder itself each time a registration is added or deleted.

The eventDispatcher objects in Figure 9-12 are depicted as rectangles (long axis is vertical). Each object has a small solid triangle inside itself, indicating that every object has the capability of accepting registrations for changes within itself (as indicated on side 6 of the object cube).

Rectangles appearing between an object (circle) and a view (rounded rectangle) coordinate and ensure consistency between the object and its view. Just as views are composites, so too are these event dispatchers. A composite object ( Customer , for example) might have a composite view consisting of the views of each of the objects occupying an instance variable of Customer (the strings in fName , lName , and MI , for example). Although it s possible for each object participating in this composition to use its own individual dispatcher to coordinate changes, it s also possible to create a single dispatcher and have each object add an event line to that dispatcher as it adds its view to the composite. Figure 9-14 illustrates this composition.

click to expand
Figure 9-14: The composite object, Customer , might use a composite dispatcher instead of each object using its own dispatcher.

In addition to the explicit elements of MVC, we also assume an outside world consisting of all the objects outside the application object. This is the realm of human being objects, legacy system objects, and operational platform objects such as hardware, operating systems, mouse managers, and keyboard managers. (Of course, any object whose name includes the term manager is immediately suspect and should be examined carefully for violations of object thinking principles.) Although it s true that everything is an object, it s equally true that many of the things in this realm operate in a very nonobject fashion.

From the perspective of the application object and the objects making up its cast of characters, the outside world is a source of information and events. It s the presumed destination of results, but whether someone actually uses the results an object was asked to provide is not of much concern. Objects live to serve. Someone on the outside asked for a service, and it was provided. The object assumes that the client knew what it was asking for and had a use for the result. This is an anthropomorphic way of saying that objects are not and should not be aware of their clients, even when those clients are not other software objects.

The application object, or one of its cast members, might require services from objects in the outside world. In that case, it might need to display itself using an update view, an implicit request to an outside world object to provide information by altering the update view. In other cases, it might need to find and send a message to an object in the outside world, usually by sending a message to the operating system object via the application object.

A composite eventDispatcher associated with the application object also handles events generated in the outside world of which objects inside the application (or the application object itself) might need notification. In Figure 9-12, the application dispatcher has three parts (view-object coordination events, outside world events, and global notification events) illustrating its composite nature.

The MVC architecture has been criticized (in some cases by those who created it), but it is an excellent example of how to organize and coordinate a group of objects without imposing any kind of centralized control. The distribution of responsibilities and the creation of special-purpose objects such as the dispatchers allow complete flexibility, even at run time. Dispatcher events, for example, can be added and deleted by sending a run-time message, as can registrations for those events. It s even possible to dynamically configure the event registration dyad at run time. MVC provides an existence proof of how the ideals of object thinking can be realized.

[1] Polymorphism ”allowing different objects to respond differently to different messages ”allows you to create classes that override (replace) a superclass method with one of their own. There are reasons for doing so, but they still create cognitive dissonance and make use of the objects containing overrides more difficult. There are better ways to achieve the same goal ”defining template or interface classes, for example.

[2] Roads connecting cities are obviously real. But the existence of a road does not mandate use by vehicles; traffic remains a potential, not a certainty .

[3] Gelernter, David. Mirror Worlds . Oxford University Press, Reprint edition (January 1993).




Microsoft Object Thinking
Object Thinking (DV-Microsoft Professional)
ISBN: 0735619654
EAN: 2147483647
Year: 2004
Pages: 88
Authors: David West

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net