Object-Oriented Design Choices
eBook - ePub

Object-Oriented Design Choices

Adair Dingle

Share book
  1. 328 pages
  2. English
  3. ePUB (mobile friendly)
  4. Available on iOS & Android
eBook - ePub

Object-Oriented Design Choices

Adair Dingle

Book details
Book preview
Table of contents
Citations

About This Book

Do modern programming languages, IDEs, and libraries make coding easy? Maybe, but coding is not design. Large-scale or expensive apps clearly require evaluation of design choices. Still, software design directly impacts code reuse and longevity even for small-scale apps with limited overhead. This text evaluates and contrasts common object-oriented designs.

A given problem may have many solutions. A developer may employ different design techniques – composition, inheritance, dependency injection, delegation, etc. – to solve a particular problem. A skilled developer can determine the costs and benefits of different design responses, even amid competing concerns. A responsible developer documents design choices as a contract with the client, delineating external and internal responsibilities. To promote effective software design, this book examines contractual, object-oriented designs for immediate and sustained use as well as code reuse. The intent of identifying design variants is to recognize and manage conflicting goals such as short versus long-term utility, stability versus flexibility, and storage versus computation. Many examples are given to evaluate and contrast different solutions and to compare C# and C++ effects. No one has a crystal ball; however, deliberate design promotes software longevity. With the prominence of legacy OO code, a clear understanding of different object-oriented designs is essential.

Design questions abound. Is code reuse better with inheritance or composition? Should composition rely on complete encapsulation? Design choices impact flexibility, efficiency, stability, longevity, and reuse, yet compilers do not enforce design and syntax does not necessarily illustrate design. Through deliberate design, or redesign when refactoring, developers construct sustainable, efficient code.

Frequently asked questions

How do I cancel my subscription?
Simply head over to the account section in settings and click on “Cancel Subscription” - it’s as simple as that. After you cancel, your membership will stay active for the remainder of the time you’ve paid for. Learn more here.
Can/how do I download books?
At the moment all of our mobile-responsive ePub books are available to download via the app. Most of our PDFs are also available to download and we're working on making the final remaining ones downloadable now. Learn more here.
What is the difference between the pricing plans?
Both plans give you full access to the library and all of Perlego’s features. The only differences are the price and subscription period: With the annual plan you’ll save around 30% compared to 12 months on the monthly plan.
What is Perlego?
We are an online textbook subscription service, where you can get access to an entire online library for less than the price of a single book per month. With over 1 million books across 1000+ topics, we’ve got you covered! Learn more here.
Do you support text-to-speech?
Look out for the read-aloud symbol on your next book to see if you can listen to it. The read-aloud tool reads text aloud for you, highlighting the text as it is being read. You can pause it, speed it up and slow it down. Learn more here.
Is Object-Oriented Design Choices an online PDF/ePUB?
Yes, you can access Object-Oriented Design Choices by Adair Dingle in PDF and/or ePUB format, as well as other popular books in Ciencia de la computación & Ciencias computacionales general. We have over one million books available in our catalogue for you to explore.

Information

II
Strategic Type Coupling

CHAPTER 4
Composition

CHAPTER OBJECTIVES

  • Define OOD relationships
  • Illustrate composition and containment
  • Examine association, ownership and cardinality
  • Introduce Dependency Injection

4.1OBJECT-ORIENTED RELATIONSHIPS

A famous quote from Aristotle, “the whole is greater than the sum of its parts”, emphasizes the power of combination. By reusing and combining types, class designers may expediently construct new types and new interfaces. A central design question is how to do so. An implied design responsibility is to manage the dependency of the whole on its parts.
OOD defines different relationships (composition, containment, and inheritance) that determine the form and flexibility of reuse. How types are connected – association, cardinality, and ownership – differentiate design options. An association between two objects may be temporary, stable, or for the lifetime of the primary object. Cardinality may reflect a one-to-one or a one-to-many relationship, may be defined at the class or object level, and may vary or be stable. Ownership implies that the primary object is responsible for a secondary object, requiring explicit decisions for allocation, release, replacement, or transfer of ownership.
Basic structural relationships are has-a (composition), holds-a (containment), and is-a (inheritance). Historic OOD discussion defined aggregation as a structure where the aggregate object contains many subobjects of the same type. Aggregation addresses only form and not intent or effect. For example, both a container and a building toy (such as a Lego set) may be described as aggregates. However, a container retains no dependency on the subobject type while a building toy is strongly dependent on its components. A container illuminates a holds-a relationship where there is little restriction on the type of subobjects held while a composite illustrates a has-a relationship with significant dependency on the subobject type. While structurally similar, holds-a and has-a may be distinguished via design details such as association, ownership, lifetime, and reuse of functionality.
The simplest relationship is none: two types do not interact. Next in simplicity is the uses-a relationship where one type uses another in a transient fashion such as call by value. Other relationships represent associations that are more enduring and suggest some type dependency.

4.2CONTAINMENT (HOLDS-A)

Standard containers model the holds-a relationship well because there is no type dependency on the subobjects. A stack provides the same utility no matter what type of data held. A stack is well-defined when empty, full, or in-between. The operations of push(), pop(), clear(), etc. function in the same manner regardless of the type of data processed. The type of data stored provides no functionality and has little or no effect on containers. The holds-a relationship reflects little or no type dependency.
Example 4.1 portrays weak type dependency: a customer holds-a gift card. The no-argument constructor zeroes out the pointer defined to hold the address of a (heap-allocated) gift card, suggesting that a customer may operate without a gift card and that not all customers have a gift card. If a customer is well-defined without a gift card, then a customer may have zero gift cards and still function as a customer. A customer is not dependent on a gift card if gift cards do not drive core functionality, or if another item, such as a free shipping certificate, may replace a gift card.
Holds-a does not require ownership. The customer may not be responsible for the destruction of a gift card, especially if ownership is temporary. Disposal of a gift card may differ by design. If the customer is the sole owner of a dynamically allocated gift card, then the gift card should be ‘destroyed’ (reference zeroed out or destructor invoked) unless ownership is transferred out. Since the presence of a gift card is optional in the customer class of Example 4.1, any method that accesses the gift card must first test for existence, as is done in replace().
Example 4.1C++ Customer Holds-A Gift Card
// transient ownership of subobject(s)
// implies memory management
// => must provide destructor
// => support or suppress copying
class Customer // replaceable gift card
// handle only, no object yet
{ GiftCard* c = 0;
public:
// assumption constructor: ownership
// of transfer assumed
Customer(GiftCard*& transfer)
{ c = transfer;
transfer = 0;
}

// no argument constructor:
// no gift card allocated
Customer() { c = 0; }

// again ownership transferred in
void replace(GiftCard*& backup)
// dispose existing card
{ if (c) delete c;
c = backup;
backup = 0;
}
˜ Customer() { if (c) delete c; }
};
A container may hold objects, copies of objects or references to objects. The objects contained may be passed in and out, transferred, or destroyed (redeemed), yielding a fluctuating cardinality across the lifetime of the container. Logically, a customer may hold a positive number of gift cards, or none. If different gift card types are available (bonus, restricted by item or calendar date, etc.), the mix of gift card types held may vary over the lifetime of a customer. Only a temporary association exists between the customer object and the gift card object.
Independent of implementation language, a containment relationship is flexible because cardinality, ownership, and association may vary. Designs differ though because of implementation language. In C++, memory management must be addressed for any object with internally allocated heap memory. The class must track ownership so that all heap-allocated memory is deallocated before objects owning the heap-allocated memory go out of scope. In all languages, aliases should be tracked so that dead objects may be reclaimed and data is not corrupted.
Copying is an essential design decision. Often, it is undesirable to copy large collections either for data integrity or performance concerns. What are the effects of supporting or suppressing copying? What does a container hold: original data, duplicates, references? Copying may be more complex when data is referenced indirectly, that is, via a reference or a pointer. What is copied? – the address holder (reference or pointer), or the actual data values?
Copy semantics should be an explicit design decision. If a C++ class neither defines nor suppresses copying, the compiler generates a default copy constructor and overloaded assignment operator that yield shallow copies, and, thus aliasing and possibly data corruption. If no decision is made in C#, copying is also shallow. Recall the difference between shallow and deep copying as examined in Chapter 3.

4.3COMPOSITION (HAS-A)

An intuitive example of composition is a signal that relies on sensors. A signal is activated when some number or proportion of its sensors are triggered. An alarm clock uses a timer as a sensor; a security light uses a motion detector, etc. Type dependency is clear: a signal is not well-defined without sensors – it is inoperable. In a has-a relation, the subObject provides key functionality and affects the state of the composing object; for example, sensors affect the state of the signal. A sensor in a failed state affects...

Table of contents