Introduction
The goal of this tip is to see how to work with a partial aggregate in a bounded context, this is an optimization for loading/saving, so we don't have to load or save the full bounded aggregate.
Story
Bob is writing a new game with superheros, they have several powers and he wants to modelize this into his new game. First, we write the interface, a superhero is an IHero
, and we have an IBatman
and ISpiderman
which both inherit from IHero
. In the game, later the player will be able to fusion the two characters to have a more powerful one, let’s call him IBatmanSpiderman
, which inherit from IBatman
and ISpiderman
. Everything is perfect, except modern languages doesn’t support multiple inheritance, so it’s not possible to create the BatmanSpiderman
class inheriting Batman
and Spiderman
.
![Image 1](/KB/architecture/855758/Composition1.PNG)
Enterprise Application
The problem still arises for enterprise applications. Imagine the company works with Domain Driven Design (DDD), where the domain are business objects they loaded in their bounded context. Due to performance reason, sometimes we want to load the full bounded context, sometimes only a part of it, some classes but not the others. One solution would be splitting the bounded context into smaller bounded contexts but it’s not always possible because we don't work anymore with a logical business set of data, so we’ll need then to join data.
Composition to Rescue
Object composition is a way to combine simple objects or data types into more complex ones. We introduce the notion of aspect, we can say an aspect is the superpower of Batman
or Spiderman
, meaning it’s the properties/methods we’d like to add to our root object. For the interface, IBatman
is either an IHero
and IBatmanAspect
, ISpiderman
is either an IHero
and ISpidermanAspect
, and IBatmanSpiderman
is an IHero
, an IBatmanAspect
and ISpidermanAspect
.So we can substitute any IHero
by an IHero
with superpowers, and for example, IBatman
has the methods of IHero
, and the methods of the IBatmanAspect
(the superpower).
For the concrete class, we can see we use composite to connect the aspect (XAspect
) to the real class (X
). In the implementation, if the BatmanAspect
has a method “Fly()
”, then Batman
should implement a method Fly()
with returning the Fly()
method of the BatmanAspect
.
![Image 2](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Conclusion
Here is the final synthetic diagram. Of course, the number of aspects is not limited, it works for methods, properties and members, and this pattern is a good substitute over multiple inheritance or working with partial domain model. But as many patterns, it has a cost of writing and a bit more complicated, as you can see in the code below:
![Image 3](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
Interface IA {}
Interface IBAspect { void MethodB(); }
Interface ICAspect { void MethodC(); }
Interface IAWithB : IA, IBAspect {}
Interface IAWithC : IA, ICAspect {}
Interface IAWithBAndC: IA, IBAspect, ICAspect {}
Class A {}
Class BAspect { void MethodB() {} }
Class CAspect { void MethodC() {} }
Class AwithB {
private BAspect bAspect = new BAspect();
public void MethodB() { return bAspect.MethodB(); }
}
Class AwithC {
private CAspect cAspect = new CAspect();
public void MethodC() { return cAspect.MethodC(); }
}
Class AwithBwithC {
private BAspect bAspect = new BAspect();
private CAspect cAspect = new CAspect();
public void MethodB() { return bAspect.MethodB(); }
public void MethodC() { return cAspect.MethodC(); }
}