Click here to Skip to main content
15,886,199 members
Articles / Programming Languages / C#

Association, Aggregation, Composition, Dependency and IOC for Beginners

Rate me:
Please Sign up or sign in to vote.
3.80/5 (15 votes)
24 May 2014CPOL5 min read 41.3K   161   20   4
Association, Aggregation, Composition, Dependency and IOC for beginners

Introduction

Association, aggregation, dependency all are developed relationship between objects. The relationship is attributed on the basis of the interaction of the objects. In this article, we will explore these relationships.

Association

Association relationship develops between objects when one object uses another object. Technically, it is a reference based relationship between two classes. One class holds a class level reference to the other class.

Example

........

C#
class Teacher
{
   
}
class Student
{
    List<Teacher> teachers;   
}

In the above example, a Teacher list is referred in the student class. The system interprets a student has multiple teachers. In this student teacher relationship, one is being used by another. But there is no part-whole relationship between them. This means neither of them is the part of another. Hence they have their own lifetime.

Aggregation

Aggregation is the same as association. Like association, this relationship develops while one object uses the other. Additionally, the objects develop a part-whole relationship and the lifetime of part does not depend on life time of whole.

Example

........

C#
class CellBattery
{

}

class CellPhone
{
    CellBattery _battery;

    void CellPhone (CellBattery battery)
    {
       _battery = battery;
     }
 }

In real life, cellphone battery is a part of cellphone. If for some reason (other than battery damage), my cellphone became non-functional, still I can use the battery in another phone. This kind of relationship implies aggregation. The lifetime of Part (cellphone battery), doesn’t depend on the lifetime of Whole (cellphone).

This real life scenario has been captured through the above coding. We are setting a CellBattery instance from outside the CellPhone class. This ensures, while the CellPhone gets destroyed (garbage collected), CellBattery survives. This CellBattery could be reused to some other CellPhone.

Difference between Association and Aggregation

Aggregation is the same as association and is often seen as a redundant relationship. Technically, aggregation doesn’t convey anything more effective about a software design than an association. The difference lies from the conceptual point of view. When the objects develop a Part-Whole relationship and the lifetime of Part doesn’t depend on the lifetime of Whole, the relationship is attributed as aggregation. But in case of association, there is no Part-Whole relationship.

Composition

In composition also, one object uses another object and they develop a Part-Whole relationship. But here the lifetime of Part depends on the lifetime of Whole.

Example

C#
class Hotel
{
        List<Room> rooms = new List<Room> ();
}

class Room
{
       
}

In real life, rooms are part of Hotel. If the Hotel is destroyed, obviously the rooms of the hotels will meet the same fate. This kind of relationship implies composition. The lifetime of Part (hotel’s room depends on the lifetime of Whole (hotel).

This real life scenario has been captured through the above coding. We are creating Rooms inside the Hotel class. This kind of implementation ensures, while the Hotel get destroyed (garbage collected), Room is also destroyed.

Dependency

Dependency can develop between objects while they are associated, aggregated or composed. This kind of relationship develops while one object invokes another object’s functionality in order to accomplish some task. Any change in the called object may break the functionality of the caller.

Example

C#
class GreetingSender
{
        EmailSender _emailSender;
        void SendGreetings(EmailSender emailSender)
        {
            _emailSender = emailSender;
            //Send Greeting through Email
            _emailSender.SendEmail();
        }
}

class EmailSender
{
        public void SendEmail()
        {
           //Send Email
        }
}

In the above example, Greetings are being sent through Email. The GreetingSender object is using the SendEmail () method of EmailSender object to accomplish it’s task. Now, if any modification ((e.g. introduction of a parameter) is made to the SendEmail() method, the SendGreetings() method of GreetingSender class will break. Also, as per the implementation, we cannot send greetings by any other mode but only through Email. That way, my GreetingSender object’s functionality is dependent on EmailSender object’s functionality. This kind of relationship is termed as dependency.

Dependency Injection

Dependency Injection is a practice about injecting functional dependency in the object. In the above example, we have injected a dependency into the GreetingSender object. We can understand the injected dependency has developed a tight coupling between GreetingSender and EmailSender objects. We cannot send greetings by any other mode but only through email. So our injected dependency is violating the design principle. As a best practice, we should inject dependency in such a way that objects will be decoupled and re-usable.

IoC (Inversion of Control)

The term Inversion of Control (IoC) refers to a programming style where a framework or runtime controls the program flow. Inversion of control means we are changing the control from normal way.

If we analyze our above dependency example, we can see the EmailSender object is controlling the GreetingSender object’s SendGreetings functionality. We cannot send greetings by any other mode but only through email. But this behavior is not desired. The implementation results to tight coupling. As a solution, we can invert the control flow and let the runtime control its SendGreetings functionality. The runtime will take the decision, which mode of communication (Email/SMS) should be used for the functionality. This kind of solution followed a principle termed as IoC. We can implement the principle using the dependency injection. We can say, IoC is the strategy and DI is the implementation.

Let’s see how we can solve our dependency problem using IOC principle.

Solution of the Dependency Problem

The GreetingSender class aggregating the EmailSender class should not depend on the direct implementation of the class. GreetingSender class should depend on the abstraction of the greeting sending functionality, rather than the concrete implementation of the functionality (sending greetings through email).

Let’s define the abstraction of “send” functionality on defining an ISender Interface:

C#
interface ISender
{
    void Send();
}

Implement the EmailSender class from this interface. Implement email sending functionality in the Send() method:

C#
public class EmailSender: ISender
{
    void Send()
    {
        //Send Email
        Console.WriteLine("Sending Email....");
    }
}

Aggregate the abstraction of “send“ functionality in the GreetingSender class:

C#
class GreetingSender
{
        ISender _sender;
        public GreetingSender(ISender sender)
        {
            _sender = sender;
        }
        void SendGreetings()
        {
            //Send Greeting 
            _sender.Send();
        }
 }

In the above implementation, we are injecting abstraction of the functionality, not the concrete functionality. With this kind of injected dependency, we made the objects loosely coupled. Here, I am not defining anywhere, what kind of communication mode (Email or SMS) , I will be used for sending greetings. In future, if I want to send Greetings through SMS, I will simply define a SMSSender class and implement the send method for sending SMSes.

C#
public class SMSSender : ISender
{
    void Send()
    {
            //Send SMS
            Console.WriteLine("Sending SMS....");
    }
 }

Now, let’s provide the concrete instances from some other module, for sending greetings using email or SMS:

C#
EmailSender emailSender = new EmailSender();
SMSSender smsSender = new SMSSender();

//Send Greeting through Email
GreetingSender greetingsEmailSender = new GreetingSender(emailSender);
greetingsEmailSender.SendGreetings();

//Send Greeting through Email
GreetingSender greetingsSMSSender = new GreetingSender(smsSender);
greetingsSMSSender.SendGreetings();
Console.ReadLine ();

Now, our greetings class is not controlled by anyone in terms of communication mode for greetings sending. The class has become loosely coupled with EmailSender/SMSsender class. The control has been inverted. The runtime has taken the control.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionSome concepts require more explanation Pin
Xernai27-May-17 7:49
Xernai27-May-17 7:49 
QuestionMy Vote of 4 Pin
codeslingerMalthius27-May-14 5:16
professionalcodeslingerMalthius27-May-14 5:16 
Question[My vote of 1] Bad explanation Pin
Thornik26-May-14 7:42
Thornik26-May-14 7:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.