Classes are the building blocks of our application. Just as we describe a single object through the attributes and operations defined in its class, we describe the relations among instances via corresponding relations among classes. For example, the millions of owner relations between people and cars can be abstracted into a single owner relation between the classes of the two.
Relations among classes describe the myriad potential relations among run-time instances.
In addition to its role as an object factory, the class can act as an object itself, with its own set of responsibilities. In this role, it provides information and services to other objects through its own interface. Often, its only clients are the instances that it has produced, but in other cases, it acts as the sole provider of data and services to a number of different kinds of objects. In fact, as shown in Figure 2, when a single object of its kind is sufficient, a class can be designed to shed its instance factory role and assume the role of the object that is needed.
Despite a shared definition, instances will often behave differently because their behavior can depend on the values of their private data or different helpers in their neighborhood.
Given the same conditions, all instances of a given class behave in the same way. They form a set of like objects. Each has a structure identical to the others, along with a set of methods that it shares with the others of its kind. Because each instance is a separate object with its own internal data areas, it can hold private data that it shares with no other. When asked to perform one of its responsibilities, it can base its response on this private data. A smart object encapsulates data that affects its decisions about how it fulfills its responsibilities.
"The object has three properties, which makes it a simple, yet powerful model building block. It has state so it can model memory. It has behavior, so that it can model dynamic processes. And it is encapsulated, so that it can hide complexity."
—Trygve Reenskaug
Each instance performs its tasks in two contexts. It behaves according to rules established by the community in which it lives, and it controls its actions according to its own private rules and data. The rules are usually embedded in the methods as conditional statements in a programming language. An object's state is reflected by data held in instance variables. These variables define the internal structure of an object and are one way an object sees others in its neighborhood; an object can hold references to others. These references allow an object to "see," and subsequently interact, with others. These references say nothing about how they interact—only that the potential exists for collaboration.