Skip to content

Composition of Classes

Composition-UML
Composition UML

Here the UML class diagram relative to the example project: we don't show the main one because we took confidence with it since the very first tutorial.

Two classes: the Employee, which we have learned to know; the Document.
And...? the mutual relationship, of course.
[The azure frame hosts just some notes, useful for infos that don't fit into UML scheme]

Look at the particular graphic connection between them: the black fulfilled rhombus attached to the logically higher class - Employee -, and the arrow pointing and attached to the Document class. This is the conventional sign for the composition.

Now look at the couple of numbers: 1 on left and 1 plus dots on right.
The meaning is so explicated: an employee object can have more than one document object, while a document one belongs only to an employee one.
[We're here talking of objects, to remark that the real relationship exists only between two real entities.]

The reason to choose the composition instead of other possible relations is that a one-way only dependence exists between two classes.
What, in our case?
Simply: the Employee is composed of Document, but has an independent life, so that it can exist without the latter.
The opposite has no worth: a Document has no sense without an owner.

So, when you see in our code - Employee class - that an employee object's creation implies a creation of a relative document (in constructor)

constructor TEmployee.Create(Name_,Surname_,DocumentTipo_,DocumentDescription_ : string); overload;
var Doc_Obj : TDocument;
begin
  self.Name:=Name_;
  self.Surname:=Surname_;

  DocumentList := TList.Create; //Create the list !!!

  Doc_Obj := TDocument.Create(DocumentTipo_,DocumentDescription_); //Create a new document
  self.DocumentList.Add(Doc_Obj);  //Add the Document object to the DocumentList
  // or just use the following for single-line instructions
  //DocumentList.Add( TDocument.Create(DocumentTipo_,DocumentDescription_) );

  self.Id := GetNextFreeId();
  counter:=counter+1;
end;

this doesn't mean what apparently could, because we can choose to separate the creation of two objects, without affecting anything vital for the code structure.
It would be simple to add a procedure apart to manage the document's creation.
We are free to choose according to the situation: here we prefer to create both of them together.

As well every employee object manages its documents with a list, because obviously more than one document exist; in the same way the main class keeps the employee objects in order.

It's now interesting to see how to manage a three-level hierarchy of classes.
Let's say immediately that it depends by your specific needs.
In this project, the file with the main class uses (recalls the code of) the Employee, and vice-versa; you can check this in code.
This choice comes from the fact that everyone of this code files require the access to the other in order to work. And this is what we've done in the first OOP proposal, which this second is based on.

Things change with Document, because of the relationship's nature set with the other two.
Here only an Employee object can access to Document class members

If you remember the mechanism of the encapsulation you'll probably know that the main class can access every public member of the Employee (and vice-versa); but not the Document's public members, until we don't include the relative file into the uses list of class.
We even could do it, but... why?
Does a TForm class need to manage a Document? no, indeed!
So you see that the code must reflect the hierarchy expressed in our project, here through the UML class diagram.

This means that even if the file with the main class can recall the Employee code (scope), it doesn't implies that it could manage all classes members that Employee could access (encapsulation rules).