5.5. More Than One

 <  Day Day Up  >  

You often work with more than one instance of an object. You can aggregate those instances using an array or a collection class. I like to distinguish between two types of aggregations. The first is termed a group , the second a collection . A group is a set of objects, typically coded using an array or a linked list. When I use the [] symbol in a class description, I am implying a group, not necessarily a particular implementation of a group.

A collection is a set of objects, typically implemented by a collection class or template ( Vector , List , etc.). Operations on a collection can include performing an operation on the collection as a whole, such as calculating the average value of an attribute for all objects in the collection, or finding a particular object matching a key value.

If you find you are performing more operations on a group, other than just passing it to other methods or enumerating it, you might want to turn it into its own class. Creating a specific collection class, instead of using classwide (static) methods, separates the concerns of operations on all the objects in a collection, from those operations on a single object. [*]

[*] A reviewer noted that this is not true in languages such as Ruby and Groovy, which support closures. Closures let you apply arbitrary operations to generic collections without resorting to creating a specific collection class.

For example, suppose that Sam wanted to keep track of the rental history of each CDDisc . You could keep the history of each rental in a RentalHistory object:

 class RentalEvent         Timestamp time_started         Timestamp time_end         Dollar rental_fee     class CDDisc         RentalEvent [] rental_history. 

If the only value Sam wanted to know was the number of times a CDDisc had been rented, there is no need for a collection. The number of times is simply the length of rental_history . However, if additional operations are to be performed with rental_history , it is time to make the attribute into its own class. For example, you might want to know the average time period for a rental, the shortest or longest rental, or the total revenue from the CDDisc. You can create a RentalHistory class to represent a collection of RentalEvent s and add these methods to that class:

 class RentalHistory         Count number_of_rentals(  )         Dollar total_revenue(  )         Days short_rental(  )         Days longest_rental(  ) 

The representation of a collection should be separate from the use of the collection. At coding time, RentalHistory can either be derived from a regular or a templated library class, or it can delegate its operations to an attribute that represents a library collection class.

Likewise, CDDisc s exist within a CDDiscCollection . In Sam's Checkout_CDDisc and Return_CDDisc use cases, we need to find a CDDisc by its physical ID. Tim and I create a CDDiscCollection interface, which looks like this:

 interface CDDiscCollection         CDDisc find_by_physical_id(PhysicalID a_physical_id)         CDDisc [] find_by_cd_release(CDRelease a_cd_release)         // Standard collection operations:         add(CDDisc a_cd_disc)         remove (CDDisc a_cd_disc) 

CDDiscCollection hides the implementation of how the collection is organized. In the actual implementation, we might use a library collection class, a database, or even a text file.

IF IT HAS COLLECTION OPERATIONS, MAKE IT A COLLECTION

Collections separate object usage from object storage and hide implementation of aggregate operations.


 <  Day Day Up  >  


Prefactoring
Prefactoring: Extreme Abstraction, Extreme Separation, Extreme Readability
ISBN: 0596008740
EAN: 2147483647
Year: 2005
Pages: 175
Authors: Ken Pugh

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