Chap.4: EXAMPLE WITH SEVERAL AGGREGATES


Let us go through a full, running sample problem which uses several aggregates. Below is the class diagram of the problem. In this simplified textual form, symbol A 0------x B represents an aggregate between A and B. This is the same as assigning many Bs to each A.

Each Department has several other Departments. In other words, Departments form a tree. Within this tree, each Department has a set of Employees and a set of Projects. The following program uses the class Aggregate from the Pattern Template Library. It creates a sample hierarchy of Departments, each with Employees and Projects, demonstrates how the data can be manipulated by removing one Employee and moving another Employee into a new position, and then prints the resulting data.

Watch for the following details:

  • For each library class, either include *.h or *.cpp, but never both.
  • We assume here that you compile with the I option set to the directory PTL/LIB, where all the *.h and *.cpp files are stored.
  • The inheritance statements may look complicated at first, but if you follow the OO diagram, they make sense. Later on, you will learn how to avoid these statements.
  • Function Department::find() is interesting because it shows how you can easily traverse the entire tree.
  • Function Department::prt() demonstrates the use of iterators for various aggregates. Don't get confused by variable offset and function prtOffset(). Both are used only to generate a nice looking printout, with deeper offset for subordinated departments. - Note how the entire data structure is compressed into the three Aggregate<> statements. These three lines are almost like a database schema: they contain all the relations between the application classes.
  • The creation of the data is a bit tedious to read, but we wanted to show you a meaningful example. The end of main(), where the data are modified, is more interesting.
  • Note that before destroying the Boss, he must be first removed from his Department, and before moving Chapeau to another Department, she also must first be removed from her original Department. If this did not happen, the library would detect a run time error.
// ---------------------------------------------------------
#include <iostream.h>
#include <string.h>
#include <mgr.h>  // always include
#include <aggregat.h>
class Department;
class Employee;
class Project;
class Department : public AggregateParent<Department,Department>,
                   public AggregateChild<Department,Department>,
                   public AggregateParent<Department,Employee>,
                   public AggregateParent<Department,Project>{
    int mDeptNo;
    void prtOffset(int i);
public:
    Department(int n){mDeptNo=n;}
    void prt(int offset); // print this and subordinate departments
    Employee* find(char *name); // recursively, find this employee
};
class Employee : public AggregateChild<Department,Employee>{ 
    char *mpName;
public:
    Employee(char *n){mpName=new char[strlen(n)+1]; strcpy(mpName,n);}
    void prt(void){cout << " " << mpName;}
    int checkName(char *n){return !strcmp(mpName,n);}
};
class Project : public AggregateChild<Department,Project>{ 
    char mProj;
public:
    Project(char p){mProj=p;}
    void prt(void){cout << " " << mProj;}
};
// ---------------------------------------------------
// The following lines declare the data organization.
// These objects do not have to be global, but making them
// global often contributes to the clarity of the code
// ---------------------------------------------------
Aggregate<Department,Department> departments;
Aggregate<Department,Employee> employees;
Aggregate<Department,Project> projects;
// ---------------------------------------------------
void Department::prtOffset(int i){
    cout << "\n";
    for(int k=0; k<i; k++) cout << "    ";
}
void Department::prt(int offset){
    Employee *pEmpl;
    Project *pProj;
    Department *pDept;
    AggregateIterator<Department,Department> deptIt;
    AggregateIterator<Department,Employee>   emplIt;
    AggregateIterator<Department,Project>    projIt;
    prtOffset(offset);
    cout << "department= " << mDeptNo;
    if(employees.head(this)){
        prtOffset(offset);
        cout << "employees:";
        ITERATE(emplIt,this,pEmpl) pEmpl->prt();
    }
    if(projects.head(this)){
        prtOffset(offset);
        cout << "projects:";
        ITERATE(projIt,this,pProj) pProj->prt();
    }
    cout << "\n";
    // recursively, print all subordinated departments
    ITERATE(deptIt,this,pDept) pDept->prt(offset+1);
}
    
Employee* Department::find(char *name){
    Employee *pEmpl;
    Department *pDept;
    AggregateIterator<Department,Department> deptIt;
    AggregateIterator<Department,Employee>   emplIt;
    // traverse the employees of this department
    ITERATE(emplIt,this,pEmpl){
        if(pEmpl->checkName(name))return pEmpl;
    }
    // recursively, search subordinate departments
    ITERATE(deptIt,this,pDept){
        pEmpl=pDept->find(name);
        if(pEmpl)return pEmpl;
    }
    return NULL;
}
    
int main(void){
    Department *pDept0,*pDept1,*pDept2;
    Employee *pEmpl;
    Project *pProj;
    
    // create a small hierarchy of departments under pDept0
    // To each department, add some employees and projects
    pDept0=new Department(200);
        pEmpl=new Employee("Head F."); employees.addTail(pDept0,pEmpl);
    pDept1=new Department(220); departments.addTail(pDept0,pDept1);
        pEmpl=new Employee("Mann H."); employees.addTail(pDept1,pEmpl);
    pDept2=new Department(225); departments.addTail(pDept1,pDept2);
        pEmpl=new Employee("Brown J."); employees.addTail(pDept2,pEmpl);
        pEmpl=new Employee("Green D."); employees.addTail(pDept2,pEmpl);
        pEmpl=new Employee("Black S."); employees.addTail(pDept2,pEmpl);
        pProj=new Project('A'); projects.addTail(pDept2,pProj);
    pDept2=new Department(228); departments.addTail(pDept1,pDept2);
        pEmpl=new Employee("Little K."); employees.addTail(pDept2,pEmpl);
        pEmpl=new Employee("Grossman A."); employees.addTail(pDept2,pEmpl);
        pProj=new Project('B'); projects.addTail(pDept2,pProj);
        pProj=new Project('C'); projects.addTail(pDept2,pProj);
    pDept1=new Department(240); departments.addTail(pDept0,pDept1);
        pEmpl=new Employee("Boss I."); employees.addTail(pDept1,pEmpl);
    pDept2=new Department(243); departments.addTail(pDept1,pDept2);
        pEmpl=new Employee("Zeller K."); employees.addTail(pDept2,pEmpl);
        pEmpl=new Employee("Chapeau A."); employees.addTail(pDept2,pEmpl);
        pEmpl=new Employee("Krpec P."); employees.addTail(pDept2,pEmpl);
        pProj=new Project('D'); projects.addTail(pDept2,pProj);
        pProj=new Project('E'); projects.addTail(pDept2,pProj);
        pProj=new Project('F'); projects.addTail(pDept2,pProj);
    // Boss I. leaves the company
    pEmpl=pDept0->find("Boss I."); 
    employees.remove(pEmpl);
    delete pEmpl;
    // Chapeau A. is promoted as head of department 240
    pEmpl=pDept2->find("Chapeau A."); 
    employees.remove(pEmpl); 
    employees.addTail(pDept1,pEmpl);
    pDept0->prt(0); // print the entire organization
    return(0);
}
/* ---------------------- results -----------------------
department= 200
employees: Head F.
    department= 220
    employees: Mann H.
        department= 225
        employees: Brown J. Green D. Black S.
        projects: A
        department= 228
        employees: Little K. Grossman A.
        projects: B C
    department= 240
    employees: Chapeau A.
        department= 243
        employees: Zeller K. Krpec P.
        projects: D E F
   ----------------------------------------------------*/

For your convenience, this program is stored in the documentation directory as PTL\DOC\TEST4.CPP, and the results are in file PTL\DOC\OUT4.