Aggregation

Good OO design and implemenation focus on code reuse. How can/should code be designed and implemented so that existing code can be reused without modification? That's one of the strengths of OO languages like C++.

Aggregation (aka composition) is a common technique for code reuse. Simply put, aggregation is using one class as a data member of another class.

This technique is used when the classes have a "has a" relationship. Consider this simple example.

Recall our now familiar DayOfYear class.

<style> body, html { background-color: #eee; } .wrap { position: absolute; perspective: 800px; perspective-origin: 50% 100px; top: 50%; left: 50%; transform: translate(-50%, -50%); } .cube { position: relative; transform-style: preserve-3d; width: 200px; margin: 0 auto; } .cube div { position: absolute; width: 200px; height: 200px; color: #000; background-color: #fff; text-align: center; line-height: 200px; font-size: 3em; box-shadow: inset 0 0 100px #999; } .shadow { position: relative; width: 200px; transform-style: preserve-3d; margin: 0 auto; } .shadow div { position: absolute; width: 200px; height: 200px; box-shadow: 0 0 200px #000; transform: rotateX(90deg) translateY(100px); transform-origin: bottom center; } .back { transform: translateZ(-100px) rotateY(180deg); } .right { transform: rotateY(-270deg) translateX(100px); transform-origin: top right; } .left { transform: rotateY(270deg) translateX(-100px); transform-origin: center left; } .top { transform: rotateX(-90deg) translateY(-100px); transform-origin: top center; } .bottom { transform: rotateX(90deg) translateY(100px); transform-origin: bottom center; } .front { transform: translateZ(100px); } @keyframes spin { from { transform: rotateY(0); } to { transform: rotateY(-360deg); } } .cube, .shadow { animation: spin 10s infinite linear; } </style> <div class="container"> <div class="text-center"> <h4>Sorry! We could not find what you were looking for</h4> <h4>Try going back to the main page <a href="https://www.csee.umbc.edu">here</a></h4> </div> </div> <div class="wrap"> <div class="shadow"> <div>&nbsp;</div> </div> </div> <div class="wrap"> <div class="cube"> <div class="front">4</div> <div class="back">4</div> <div class="top">0</div> <div class="bottom">0</div> <div class="left">0</div> <div class="right">0</div> </div> </div> <!-- <div class="wpgdprc-consent-bar wpgdprc-consent-bar--position-bottom" style="display: none;"> <div class="wpgdprc-consent-bar__inner"> <div class="wpgdprc-consent-bar__container"> <div class="wpgdprc-consent-bar__content"> <div class="wpgdprc-consent-bar__column wpgdprc-consent-bar__column--notice"> <div class="wpgdprc-consent-bar__notice"><p>This site uses functional cookies and external scripts to improve your experience.</p> </div> </div> <div class="wpgdprc-consent-bar__column wpgdprc-consent-bar__column--settings"> <button type="button" class="wpgdprc-button wpgdprc-button--settings" data-micromodal-trigger="wpgdprc-consent-modal" aria-expanded="false" aria-haspopup="true" > Settings and Information </button> </div> <div class="wpgdprc-consent-bar__column wpgdprc-consent-bar__column--accept"> <button type="button" class="wpgdprc-button wpgdprc-button--accept"> Accept </button> </div> </div> </div> </div> </div> <div class="wpgdprc wpgdprc-consent-modal" id="wpgdprc-consent-modal" aria-hidden="true"> <div class="wpgdprc-consent-modal__overlay" tabindex="-1" data-micromodal-close> <div class="wpgdprc-consent-modal__inner" role="dialog" aria-modal="true"> <div class="wpgdprc-consent-modal__header"> <p class="wpgdprc-consent-modal__title">Privacy settings</p> <button class="wpgdprc-consent-modal__close" aria-label="Close popup" data-micromodal-close> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M193.94 256L296.5 153.44l21.15-21.15c3.12-3.12 3.12-8.19 0-11.31l-22.63-22.63c-3.12-3.12-8.19-3.12-11.31 0L160 222.06 36.29 98.34c-3.12-3.12-8.19-3.12-11.31 0L2.34 120.97c-3.12 3.12-3.12 8.19 0 11.31L126.06 256 2.34 379.71c-3.12 3.12-3.12 8.19 0 11.31l22.63 22.63c3.12 3.12 8.19 3.12 11.31 0L160 289.94 262.56 392.5l21.15 21.15c3.12 3.12 8.19 3.12 11.31 0l22.63-22.63c3.12-3.12 3.12-8.19 0-11.31L193.94 256z"/></svg> </button> </div> <div class="wpgdprc-consent-modal__body"> <nav class="wpgdprc-consent-modal__navigation"> <ul class="wpgdprc-consent-modal__navigation-list"> <li class="wpgdprc-consent-modal__navigation-item"> <button class="wpgdprc-consent-modal__navigation-button wpgdprc-consent-modal__navigation-button--active" data-target="description">Privacy Settings and Information</button> </li> <li> <button class="wpgdprc-consent-modal__navigation-button" data-target="1">Google Analytics</button> </li> </ul> </nav> <div class="wpgdprc-consent-modal__information"> <div class="wpgdprc-consent-modal__description wpgdprc-consent-modal__description--active" data-target="description"> <p class="wpgdprc-consent-modal__title wpgdprc-consent-modal__title--description">Privacy Settings and Information</p> <div class="wpgdprc-content-modal__content"> <p>This site uses functional cookies and external scripts to improve your experience. Which cookies and scripts are used and how they impact your visit is specified on the left. Your choices will not impact your visit.</p> <p><strong>Details</strong></p> <p><em>NOTE:</em> Third-party Google scripts on this website may have access to cross-site third-party cookies under the google.com domain. We, the CSEE Department, do not access, read, or write these third-party cookies, and as a result, we do not control their presence on your browser. You may block them by using a third-party cookie blocker in your browser.</p> <p>If you click Accept below to accept the general cookie consent, then a &#8220;wpgdprc-consent&#8221; cookie will be stored on your browser, to record your general consent.</p> <p>If you click Accept below to accept the general cookie consent, and also have Google Analytics cookies enabled (on the sidebar to the left), the CSEE Department website will store and access Google Analytics cookies on your browser. We use the data from these cookies to collect information on website usage statistics and improve user experience. If you do not wish to allow Google Analytics cookies on your browser, then either do not click Accept on the bottom bar, or disable Google Analytics on the left.</p> <p>If you log in to this website, then several Wordpress cookies and session variables will be stored on your browser. Accessing the login screen constitutes your consent to have Wordpress cookies and session variables stored on your computer.</p> <p><strong>External Scripts</strong></p> <p>The CSEE Department website makes use of several external scripts to improve user experience. These include, but are not necessarily limited to: Google Calendar, Google Analytics, and ReCAPTCHA. If you choose to use this website, then you agree to allow these scripts to be loaded and executed.</p> <p><strong>External Links</strong></p> <p>Our service may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by us. Therefore, we strongly advise you to review the Privacy Policy of these websites. We have no control over, and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.</p> <p><span class="wpgdprc-text--warning"><strong>NOTE:</strong> These settings will only apply to the browser and device you are currently using.</span></p> </div> </div> <div class="wpgdprc-consent-modal__description" data-target="1"> <p class="wpgdprc-consent-modal__title wpgdprc-consent-modal__title--description">Google Analytics</p> <div class="wpgdprc-content-modal__content"> <p>Enables Google Analytics.</p> </div> <div class="wpgdprc-content-modal__options"> <div class="wpgdprc-checkbox"> <label class="wpgdprc-switch wpgdprc-switch--column wpgdprc-switch--border" for="1"> <span class="wpgdprc-switch__text">Enable?</span> <span class="wpgdprc-switch__switch"> <input class="wpgdprc-switch__input" type="checkbox" id="1" name="1" value="1" /> <span class="wpgdprc-switch__slider round"> <span data-icon="check" class="icon--wrap"> <svg class="icon"> <use href=https://redirect.cs.umbc.edu/wp-content/plugins/wp-gdpr-compliance/Assets/icons//sprite-fontawesome-pro-regular.svg#check></use> </svg> </span> <span data-icon="times" class="icon--wrap"> <svg class="icon"> <use href=https://redirect.cs.umbc.edu/wp-content/plugins/wp-gdpr-compliance/Assets/icons//sprite-fontawesome-pro-regular.svg#times></use> </svg> </span> </span> </span> </label> </div> </div> </div> </div> </div> <div class="wpgdprc-consent-modal__footer"> <div class="wpgdprc-consent-modal__footer__information"> <a href="https://cookieinformation.com/?utm_campaign=van-ons-go-premium&#038;utm_source=van-ons-wp&#038;utm_medium=referral" target="_blank">Powered by Cookie Information</a> </div> <button class="wpgdprc-button wpgdprc-button--secondary">Save my settings</button> </div> </div> </div> </div> <div class="footer"> <div class="container box"> <p style="text-align: left"> <span> ©2024 University of Maryland Baltimore County Computer Science and Electrical Engineering Department<br> </span> <span> 1000 Hilltop Circle, ITE 325, Baltimore, Maryland 21250 | 410-455-3500 | <a href="https://plus.google.com/100554857285792052165"><i class="fa fa-google" title="Google Plus Link"></i></a> <a href="https://www.facebook.com/pages/UMBC-CSEE-Department/104803409392"><i class="fa fa-facebook" title="Facebook Link"></i></a> <a href="https://twitter.com/umbccsee"><i class="fa fa-twitter" title="Twitter Link"></i></a> <a href="https://calendar.google.com/calendar/embed?src=umbccsee@gmail.com"><i class="fa fa-calendar" title="Google Calendar Link"></i></a> <a href="https://www.csee.umbc.edu/feed"><i class="fa fa-rss" title="RSS Link"></i></a> </span> <br> <a href="http://coeit.umbc.edu/">College of Engineering and Information Technology</a> | <a href="/about/contact-us">Contact Us</a> | <a href="https://umbc.edu/go/equal-opportunity">Equal Opportunity</a> | <a href="https://enrollment.umbc.edu/consumer_info/">Consumer Information</a> | <a href="https://accessibility.umbc.edu/digital-content-accessibility/website-accessibility-at-umbc/">Accessibility</a> </p> </div> </div> </body> </html> --> Here's how it might be used in a new class. Note that a Vactation "has a" DayOfYear. Also note the following about the code
  1. The Vacation constructor uses the initialization list to call the DayOfYear constructor. If it did not do so, then DayOfYear's default constructor would be automatically be called.
  2. In this case, the Vacation class is a USER of the DayOfYear class and is therefore limited to using DayOfYear's public methods.
  3. Note that in some cases, the methods of the Vacation class simply call a method of the DayOfYear class. A classic example of code reuse.
  4. Note the return type of Vacation::GetDayOfYear.
    Returning by reference to const prevents copying of the DayOfYear object and does not allow the user to change Vacation's private data (m_startDOY) by using the reference.
    More on this in class.
#ifndef VACATION_H #define VACATION_H #include "DayOfYear.h" class Vacation { public: Vacation( int startMonth, int startDay, int duration); void Set( int newMonth, int newDay); void Set( int newDuration); const DayOfYear& GetDayOfYear( ) const; int GetMonth( ) const; int GetDay( ) const; int GetDuration ( ) const; bool IsValid ( ) const; void Input ( ); void Output ( ) const; private: DayOfYear m_startDOY; int m_nrDays; bool m_isValid; }; #endif and here's the impmlementation of the Vacation class from Vacation.cpp. The usual checking of pre-conditions is removed so that we can focus on the aggregation aspects of the code. //----------------------- // File: Vacation.cpp // Author: D. Frey // Date: 7/11/03 // Section: 1234 // Email: frey@cs.umbc.edu // Project: none // // This code illustrates the implementation of // a class which uses aggregation (aka composition) //------------------------------------------------ #include <iostream> #include <cstdlib> #include "DayOfYear.h" #include "Vacation.h" using namespace std; //---------------------- // Vacation constructor // PreConditions // none // PostCondition // a new object is created with the // user specified values // //---------------------------- // Note the use of the initialization list // to invoke the DayOfYear constructor for m_startDOY // // alternate implementations are also possible // --- what might some of them be? // --- why is this one best? // //---------------------- Vacation::Vacation( int month, int day, int nrDays) : m_startDOY( month, day), m_nrDays( nrDays) { if (m_nrDays <= 0) m_isValid = false; else m_isValid = m_startDOY.IsValid( ); } //----------------------------------- // Set( ) -- a mutator // PreConditions: // 1 <= month <= 12 // 1 <= day <= 31 // PostConditions // month and day changed // // Note the use of DayOfYear's method //------------------------------------- void Vacation::Set (int newMonth, int newDay) { m_startDOY.Set( newMonth, newDay); m_isValid = m_startDOY.IsValid( ); } //----------------------------------- // Set( ) -- a mutator // PreConditions: // 1 <= day // PostConditions // vacation duration changed // //------------------------------------- void Vacation::Set (int newNrDays) { m_nrDays = newNrDays; m_isValid = (m_nrDays > 0); } //----------------------------------- // GetDayOfYear( ) -- an accessor // PreConditions: // none // PostConditions // returns the DayOfYear via reference to const // // Note the return type // //------------------------------------- const DayOfYear& Vacation::GetDayOfYear ( ) const { return m_startDOY; } //----------------------------------- // GetMonth( ) -- an accessor // PreConditions: // none // PostConditions // returns 1 = Jan, 2 = Feb, etc // // Note the use of DayOfYear's method //------------------------------------- int Vacation::GetMonth ( ) const { return m_startDOY.GetMonthNumber( ); } //----------------------------------- // GetDay( ) -- an accessor // PreConditions: // none // PostConditions // returns day of month that vacation begins // // Note the use of DayOfYear's method //------------------------------------- int Vacation::GetDay ( ) const { return m_startDOY.GetDay( ); } //----------------------------------- // GetDuration( ) -- an accessor // PreConditions: // none // PostConditions // returns vacation duration // //------------------------------------- int Vacation::GetDuration ( ) const { return m_nrDays; } //----------------------------------- // IsValid // PreConditions: // none // PostConditions // returns true if the Vacation data is valid // //------------------------------------- int Vacation::GetDuration ( ) const { return m_isValid; } //-------------------------------- // Input // Preconditions: // none // PostCondition: // user prompted for month, day and duration // which are saved in private data // // Note use of DayOfYear's method //------------------------------------ void Vacation::Input ( ) { m_startDOY.Input(); cout << "Enter number of days: "; cin >> m_nrDays; if (m_nrDays < 1) { cout << "Invalid vacation duration" << endl; exit ( 1 ); } } //-------------------------------- // Output // Preconditions: // none // PostCondition: // month, day and duration displayed // // Note use of DayOfYear's method //------------------------------------ void Vacation::Output ( ) const { m_startDOY.Output(); cout << "\nDuration: " << m_nrDays << endl; }

Keeping perspective

When multiple classes are involved in a design as in this case, it's important to keep the proper perspective when implementing these classes.

As mentioned above, Vaction is a USER of the DayOfYear class and is limited to using DayOfYear's public methods. Vaction has no special privileges or permission which allow it to access the private data members of the DayOfYear class.

It's also important to remember that the DayOfYear class has no "knowledge" of how it's being used. There should be no new methods or coded added to the DayOfYear class that are in anyway specific to Vacation.

It's important that "boundaries" between classes (what each class knows and doesn't know about the others) not be breached.


[CSEE] | [CMSC202] | [Spring '07 CMSC202]             Last Modified: 28 Aug 2006 10:15:53 EDT