Association relationships between objects

An Association relationship between two objects can have different levels of dependency. In some situations, an object just knows about the existance of another and works with it while in other scenarios it may be the one in charge of all its lifetime. Depending on how much dependency there is between those objects we can define 3 types of Association Relationship:

Composition: The owner controls the child lifetime.

Aggregation: The main object has inside of it the other but doesn’t control its lifetime.

Delegation: The main object just knows about the existence of the other one.

Composition

This is a has-a relationship, meaning the main object has a child object type inside of it. With Composition, the life-cycle of the objects that compose an object ends when the main object is disposed. For example, if we have a House object with Window objects that are instantiated when the house is and only exist inside the House object, never outside of it.

public class ComposedClass
{
private List<Window> Windows;

public ComposedClass()
{
Windows.Add(new Window());
Windows.Add(new Window());
}
}

public class Window{}

Aggregation

This is another has-a relationship as it has the other object as a child. With Aggregation, subobjects may exist outside the main object. Let’s imagine we now have a remodeling house company. Now we need methods .AddWindow() and .RemoveWindow() at House object, with this, Windows will exist outside the House lifecycle, which means House is built by aggregation, as Windows need to be assigned and exist outside the House context.

public class AggregationClass
{
private List<Window> Windows;

public AggregationClass() {}

AddWindow(Window window)
{
Windows.Add(window);
}

RemoveWindow(Window window)
{
Windows.Remove(window);
}
}

public class Window{}

//
// We could also aggregate them in the constructor:
//
public class AggregationClass
{
private List<Window> Windows;

public AggregationClass(Window window)
{
Windows.Add(window);
}
}

public class Window{}

Delegation

With Delegation, an object will expose a functionality that another object will implement. Imagine we implement the method .Register() in the House object, but House will call another to perform the task though we will not know that from the outside, we will just know we need to call House.Register(). The relationship between them will exist while the process is being taken, that is, we may instantiate the Government object inside House.Register(), once instantiated we will call its Government.Register(this) to delegate the action, and after the action is finished, we will dispose the Government object so that House and Government objects are not related anymore.

public interface IGovernmentRegisterable
{
string Address { get; set; }
string Owner { get; set; }
}
public class House : IGovernmentRegisterable
{
public string Address { get; set; }
public string Owner { get; set; }

public void Register()
{
Government gov = new Government();
gov.Register(this);
}
}

public class Government
{
public void Register(IGovernmentRegisterable sentObject)
{
// Do something
}
}

We can use Delegation when we need to reuse some functionality between different classes but there isn’t any real relationship between them apart than processing that operation. Normally we will send the “caller” object as a parameter, but as different classes will use that method we’ll use interfaces to make those classes of the same type and able to call the same method sending themselves as parameters.