Designing an application using Object Oriented Programming is inevitable due to the features it provides, like inheritance, polymorphism, encapsulation and so on. Apart from these concepts, it is very important to understand some logical concepts along with technical concepts so that writing the code is easy, clean and re-usable. This article will explain some of the concepts we use in most of the classes that we write, even if we don't know we have implemented the concept.
Relationships, as the name suggests, defines the dependency/association/same kind in the components of a system in real life. The same for Object Oriented Programming that involve many of classes and most of these classes are somehow dependent/associated or similar to one or the other class. So broadly speaking, we have the concept of relationships with the following 3 categories:
- Dependency: also called a using relationship, which means, one class is dependent on another class.
- Generalization: also called an "is-a-kind-of" relationship.
- Association: also called a "has-a" relationship that says one class is somehow associated with another class.
Association is a special kind of relationship and is sub-divided into the two specialized concepts of Aggregation and Composition.
To explain these concepts, I will refer to my understanding of my study, along with examples from the book named "The Unified Modeling Language User Guide" by Grady Booch, James Ramabaugh and Ivar Jacobson.
So let's start with it.
Dependency is defined as a relation between two classes, where one class depends on another class but another class may or not may depend on the first class.So any change in one of the classes may affect the functionality of the other class, that depends on the first one.
For examle, we have a Customer class and an Order class. When we need to save a new order, we need to save it corresponding to a customer. In order to do so, our Order class will need a reference to the Customer class and save its data. So in this case, our Order class is dependent on the Customer class. In the future, if any change are made to the Customer class, it may result in changes to the Order class. See the code below:
In the code above, we have a CustomerId as a GUID. The Order class uses this customer instance. If we change the data type of the CustomerId from GUID to integer, it will affect the Order class. This kind of relation is known as a Dependency and is represented by the following symbol in a UML representation:
All of us know about the concept of inheritance. It is nothing but a kind of generalization. We define it simply with a base class having some properties, functions and so on. A new class will be derived from this base class and the child class will have access to all the functionality of the base or parent class (of course depending on the access modifiers defined on the base class members).
It is also referred to as a "is-a-kind-of" or "is-a" relationship; that means that the child class is-a-kind-of a base class. This provides the ability to define common properties for derived classes in a common place and use of them depends on the derived class requirements.
For example: we have a base class named Vehicle and a derived class named Car, from the base class. So Car will have access to all the functions, properties and so on of the base class Vehicle (depending on the access modifiers defined for base class members). See the code below:
Here we have common properties like color and price in the base class that can be set depending on the derived class's requirements. Apart from these, it will add its specific property named Discount. But this class will not have access to the base class property VehicleType, since it is a private type. The same will be applicable for any other class that derives from the Vehicle class and any other member defined in the base class. Generalization is represented by the following symbol in UML:
Association is defined as a structural relationship, that conceptually means that the two components are linked to each other. This kind of relation is also referred to as a using relationship, where one class instance uses the other class instance or vice-versa, or both may be using each other. But the main point is, the lifetime of the instances of the two classes are independent of each other and there is no ownership between two classes.
For example, consider the same example of a Student-Teacher relationship. Conceptually speaking, each student can be associated with multiple teachers and each teacher can be associated with multiple students. Now to explain this relationship in terms of Object Oriented Programming, see the code below:
Here, we have a single student instance "_student". This student can have multiple teacher class instances associated with it, in other words "_teacher1" and "_teacher2".
- First, both of these instances are being created outside the student class. So their lifetime is independent of the lifetime of the instance of the student. So even if "_student" is disposed of explicitly, we can still have the teacher class instances as alive.
- Secondly, any other student instance, say _student2, can also have the same instances of teacher, in other words "_teacher1" and "_teacher2" associated with it. So we can also say that no instance of student is a parent of any instance of teacher. So there is no ownership of instances in the association.
Similarly, we can have the reverse case, where we have a teacher instance "_teacher1" associated with "_student1" and "_student2", and so on. The same student instances can be associated with another teacher instance, say "_teacher2".
This association is represented by the following symbol in UML:
So that described association. Now for the specialized cases of association, aggregation and composition.
- Aggregation: Aggregation is the same as association but with an additional point that there is an ownership of the instances, unlike association where there was no ownership of the instances. To understand it better, let's add another class named Department to our example explained above.
If we talk about the relation between Teacher and Department then conceptually, a Department can have multiple Teachers associated with it but each Teacher can belong to only one Department at a time. Now to explain this relationship in terms of Object Oriented Programming, see the code below:
Here, we have a department instance "_department1" and multiple instances of teacher, in other words "_teacher1" and "_teacher2".
- First, the lifetime of "_teacher1" and "_teacher2" instances are independent of the lifetime of a "_department1" instance, since they are instantiated outside the department class. So even if a "_department1" instance is disposed if, "_teacher1" and "_teacher2" instances may continue to exist.
- Secondly, "_department1" can have multiple instances of teacher associated with it, but the reverse is not true, in other words "_teacher1" and "_teacher2" can belong to "_department1" only. They cannot belong to any other instance like department2. So "_department1" becomes the owner of the "_teacher1" and "_teacher2" instances. So here the ownership exists.
Aggregation is also referred to as a Weak Association and is represented by the following symbol in UML representation:
- Composition: This is the same as that of aggregation, but with the additional point that the lifetime of the child instance is dependent on the owner or the parent class instance. To the same code above, let's add another class named University.
So in this case also, conceptually, a university can have multiple departments in it. But each department can belong to a single university only. Now to explain this relationship in terms of Object Oriented Programming, see the code below:
- First, each department instance, in other words "_department1" and "_department2", can belong only to a single university instance at a time, _university1. But a university instance can have multiple department instances attached to it. So this makes the "_university1" instance the owner of the "_department1" and "_department2" instances. So this is the inherited feature of the aggregation in composition.
- Secondly, here the lifetime of department instances are dependent on the instances of university, since they are being created inside the university class. So when the "_university1" instance is disposed of the "_department1" and "_department2" instances are also killed. This is the composition concept.
Composition is also referred to as a Strong Association or Death relationship and is represented by the following symbol in UML representation:
So if we closely observe the concepts of Association, Aggregation and Composition, we can say that composition is a subset of association and aggregation and aggregation is a subset of association. In other wors, Association is a super-set of aggregation and composition can be represented as:
So this was all about these concepts and we can say that we were using these concepts in our programming but were not aware of their actual existence.