設計思維點滴二:classes and objects

What Is and What Isn’t an Object

 

define control objects as “the ones that unite courses of events and thus

 will carry on communication with other objects

 

“an object represents an individual, identifiable
item, unit, or entity, either real or abstract, with a well-defined role in the
problem domain”

 

An object has state, exhibits some well-defined behavior,
and has a unique identity.

 

An object is an entity that has state, behavior, and identity. The structure and
behavior of similar objects are defined in their common class. The terms instance
and object are interchangeable.

 

State

 

The state of an object encompasses all of the (usually static) properties of the
object plus the current (usually dynamic) values of each of these properties.

 

A property is an inherent or distinctive characteristic, trait, quality, or feature that
contributes to making an object uniquely that object.

 

we distinguish between objects and simple values: Simple quantities
such as the number 3 are “atemporal, unchangeable, and non-instantiated,”
whereas objects “exist in time, are changeable, have state, are instantiated, and
can be created, destroyed, and shared”

Behavior

Behavior is how an object acts and reacts, in terms of its state changes and message
passing.

 

The state of an object represents the cumulative results of its behavior considering the behavior

 

Operations

An operation denotes a service that a class offers to its clients. In practice, we
have found that a client typically performs five kinds of operations on an object.2
The three most common kinds of operations are the following:
■ Modifier: an operation that alters the state of an object
■ Selector: an operation that accesses the state of an object but does not alter
the state
■ Iterator: an operation that permits all parts of an object to be accessed in
some well-defined order
Two other kinds of operations are common; they represent the infrastructure necessary
to create and destroy instances of a class.
■ Constructor: an operation that creates an object and/or initializes its state
■ Destructor: an operation that frees the state of an object and/or destroys the
object itself

 

Roles and Responsibilities

A role is a mask that an object wears  and so defines a contract between an

abstraction and its clients. In other words, we may say that the
state and behavior of an object collectively define the roles that an object may
play in the world, which in turn fulfill the abstraction’s responsibilities.

 

“Responsibilities are meant to convey a sense of the purpose of an object and its
place in the system. The responsibilities of an object are all the services it provides
for all of the contracts it supports”

 

Objects play many different roles during their lifetimes.

 

Continuing the machine metaphor, we may classify objects as either active or passive.
An active object is one that encompasses its own thread of control, whereas
a passive object does not. Active objects are generally autonomous, meaning that
they can exhibit some behavior without being operated on by another object.
Passive objects, on the other hand, can undergo a state change only when explicitly
acted on. In this manner, the active objects in our system serve as the roots of
control. If our system involves multiple threads of control, we will usually have
multiple active objects. Sequential systems, on the other hand, usually have
exactly one active object, such as a main object responsible for managing an event
loop that dispatches messages. In such architectures, all other objects are passive,
and their behavior is ultimately triggered by messages from the one active object.
In other kinds of sequential system architectures (such as transaction-processing
systems), there is no obvious central active object, so control tends to be distributed
throughout the system’s passive objects.

Identity:distinct from aliases;

structural sharing, meaning that a
given object can be named in more than one way; in other words, there are
aliases to the object. Structural sharing is the source of many problems in
object-oriented programming. Failure to recognize the side effects of operating
on an object through aliases often leads to memory leaks, memoryaccess
violations, and, even worse, unexpected state changes.

 

Relationships among Objects

Links:lose couple

An object collaborates with other
objects through its links to these objects. Stated another way, a link denotes the
specific association through which one object (the client) applies the services of
another object (the supplier), or through which one object may navigate to
another.

 

As a participant in a link, an object may play one of three roles.
1. Controller: This object can operate on other objects but is not operated on
by other objects. In some contexts, the terms active object and controller are
interchangeable.
2. Server: This object doesn’t operate on other objects; it is only operated on
by other objects.
3. Proxy: This object can both operate on other objects and be operated on by
other objects. A proxy is usually created to represent a real-world object in
the domain of the application.

Synchronization :active objects self-controlled and passive objects have 3 kinds of implementing sync

active objects embody
their own thread of control, so we expect their semantics to be guaranteed in the
presence of other active objects. However, when one active object has a link to a
passive one, we must choose one of three approaches to synchronization.
1. Sequential: The semantics of the passive object are guaranteed only in the
presence of a single active object at a time.
2. Guarded: The semantics of the passive object are guaranteed in the presence
of multiple threads of control, but the active clients must collaborate to
achieve mutual exclusion.
3. Concurrent: The semantics of the passive object are guaranteed in the presence
of multiple threads of control, and the supplier guarantees mutual
exclusion.

 

Aggregation :better encapsulation;denote whole/part relationship better than physical aggregation of the parts

There are clear trade-offs between links and aggregation. Aggregation is sometimes
better because it encapsulates parts as secrets of the whole. Links are
sometimes better because they permit looser coupling among objects. Intelligent
engineering decisions require careful weighing of these two factors.

 

The Nature of a Class :everything is class ;high abstraction  call a cluster of class a component

 

In the context of object-oriented analysis and design, we define a class as follows:
A class is a set of objects that share a common structure, common behavior, and
common semantics.
A single object is simply an instance of a class.

 

For example, at a sufficiently high level of abstraction, a GUI
framework, a database, and an entire inventory system are all conceptually

individual objects, none of which can be expressed as a single class.4 Instead,
it is far better for us to capture these abstractions as a cluster of classes whose
instances collaborate to provide the desired structure and behavior. So we
calls such a cluster a component

 

Interface and Implementation

We can further divide the interface of a class into four parts:
1. Public: a declaration that is accessible to all clients
2. Protected: a declaration that is accessible only to the class itself and its subclasses

3. Private: a declaration that is accessible only to the class itself
4. Package: a declaration that is accessible only by classes in the same package

 

One might be tempted to express such abstractions in a single class, but the granularity
for reuse and change is too coarse. Having a “fat” interface is bad practice because most
clients will want to reference only a small subset of the services provided. Furthermore,
changing one part of a huge interface obsolesces every client, even those that don’t care
about the parts that changed. Nesting classes doesn’t eliminate these problems; it only defers
them.

 

The constants and variables that form the representation of a class are known by
various terms, depending on the particular language we use.

instance variable/field/data member

Association

Semantic Dependencies

Multiplicity

1. One-to-one
2. One-to-many
3. Many-to-many

Inheritance

Polymorphism is most useful when there are many classes with the same protocols.

With polymorphism, large case statements are unnecessary because each
object implicitly knows its own type.

 

An alternate approach to inheritance involves a language mechanism
called delegation, in which objects delegate their behavior to related objects.

 

In C++, one may declare
functions having the same names, as long as their invocations can be distinguished
by their signatures, consisting of the number and types of their arguments

(in C++, unlike Ada, the type of a function’s returned value is not considered in
overload resolution).

 

Without polymorphism, the developer ends up writing code consisting of large
case or switch statements. Without it, we cannot create a hierarchy of classes for
the various kinds of telemetry data; rather, we have to define a single, monolithic
variant record encompassing the properties associated with all the kinds of data.
To distinguish one variant from another, we have to examine the tag associated
with the record.

 

Polymorphism and late binding go hand in hand. In the presence of polymorphism,
the binding of a method to a name is not determined until execution. In
C++, the developer may control whether a member function uses early or late
binding. Specifically, if the method is declared as virtual, then late binding is
employed, and the function is considered to be polymorphic. If this virtual declaration
is omitted, then the method uses early binding and thus can be resolved at
the time of compilation.

Multiple Inheritance:handle name collisions &repeated inheritance

Designing a suitable class structure involving inheritance, and especially
involving multiple inheritance, is a difficult task. This is often an incremental and
iterative process. Two problems present themselves when we have multiple inheritance:
How do we deal with name collisions from different superclasses, and
how do we handle repeated inheritance?

 

we may define a mixin as a class that embodies a single,
focused behavior and is used to augment the behavior of some other class via
inheritance. The behavior of a mixin is usually completely orthogonal to the
behavior of the classes with which it is combined. A class that is constructed primarily
by inheriting from mixins and does not add its own structure or behavior is
called an aggregate class.

Aggregation:distinguish inheritance("is a") through litmus test

A less direct kind of aggregation is also possible, called composition, which is
containment by reference.

Aggregation asserts a direction to the whole/part relationship.

The Role of Classes and Objects in Analysis and Design

the design of classes and objects is an incremental, iterative process.
During analysis and the early stages of design, the developer has two primary
tasks:
1. Identify the classes that form the vocabulary of the problem domain
2. Invent the structures whereby sets of objects work together to provide the
behaviors that satisfy the requirements of the problem
Collectively, we call such classes and objects the key abstractions of the problem,
and we call these cooperative structures the mechanisms of the implementation.
During these phases of development, the developer must focus on the outside
view of these key abstractions and mechanisms. This view represents the logical
framework of the system and therefore encompasses the class structure and object
structure of the system. In the later stages of design and then moving into implementation,
the task of the developer changes: The focus is on the inside view of
these key abstractions and mechanisms, involving their physical representation.

Measuring the Quality of an Abstraction


How can one know if a given class or object is well designed? We suggest five
meaningful metrics:

1. Coupling
2. Cohesion
3. Sufficiency
4. Completeness
5. Primitiveness

choosing operation

Functional Semantics

It is common in object-oriented development to design the methods of a class as a
whole because all these methods cooperate to form the entire protocol of the
abstraction. Thus, given some desired behavior, we must decide in which class to
place it.criteria to be considered when making such a decision.
■ Reusability: Would this behavior be more useful in more than one context?
■ Complexity: How difficult is it to implement the behavior?
■ Applicability: How relevant is the behavior to the type in which it might be
placed?
■ Implementation knowledge: Does the behavior’s implementation depend on
the internal details of a type?

Time and Space Semantics

Once we have established the existence of a particular operation and defined its
functional semantics, we must decide on its time and space semantics. This
means that we must specify our decisions about the amount of time it takes to
complete an operation and the amount of storage it needs. Such decisions are
often expressed in terms of best, average, and worst cases, with the worst case
specifying an upper limit on what is acceptable.

Choosing Relationships

Law of Demeter, which states that "the methods of a class should not depend in
any way on the structure of any class, except the immediate (top-level) structure
of their own class. Further, each method should send messages to objects belonging
to a very limited set of classes only”

 

We must make similar trade-offs among inheritance, aggregation, and dependency
relationships.

Mechanisms and Visibility

Deciding on the relationship among objects is mainly a matter of designing the
mechanisms whereby these objects interact.

Choosing Implementations

Representation

The representation of a class or object should almost always be one of the encapsulated
secrets of the abstraction. This makes it possible to change the representation
(e.g., to alter the time and space semantics) without violating any of the functional

assumptions that clients may have made

 

“The choice of representation is often a fairly difficult one, and it is not uniquely determined
by the facilities available. It must always be taken in light of the operations
that are to be performed upon the data”

Packaging

Similar issues apply to the declaration of classes and objects within modules. The
competing requirements of visibility and information hiding usually guide our
design decisions about where to declare classes and objects. Generally, we seek to
build functionally cohesive, loosely coupled modules. Many nontechnical factors
influence these decisions, such as matters of reuse, security, and documentation.
Like the design of classes and objects, module design is not to be taken lightly.

Summary

■ An object has state, behavior, and identity.
■ The structure and behavior of similar objects are defined in their common
class.
■ The state of an object encompasses all of the (usually static) properties of
the object plus the current (usually dynamic) values of each of these
properties.
■ Behavior is how an object acts and reacts in terms of its state changes and
message passing.
■ Identity is the property of an object that distinguishes it from all other
objects.
■ A class is a set of objects that share a common structure and a common
behavior.
■ The three kinds of relationships include association, inheritance, and
aggregation.
■ Key abstractions are the classes and objects that form the vocabulary of the
problem domain.
■ A mechanism is a structure whereby a set of objects work together to provide
a behavior that satisfies some requirement of the problem.
■ The quality of an abstraction may be measured by its coupling, cohesion,
sufficiency, completeness, and primitiveness.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章