The goal of modeling domain concepts through objects set by OOP has for a long time been handled in insufficient ways. What is the fundamental problem with how we have tried to do this so far? Is there a better way to deal with it? In this article we introduce the concept of Composite Oriented Programing, and show how it avoids the issues with OOP and reignites the hope of being able to compose domain models using reusable pieces.
The problem
Who am I? I am many things. Sometimes I’m a software developer, creating new
software. Sometimes I’m a software developer who makes presentations on Java-related topics. But sometimes I’m something completely different, such as a customer to a bank, or an alumni at a university. I am many things, one for each context. Each of these contexts require me to use a different interface to interact with it, with operations that are specific to the context. In all these contexts, with all these different interfaces, I am however one and the same object. There’s not one me at the bank, and another writing software. I’m not clonable, at least not in the near, foreseeable future.
The typical solution
And yet, if I was to be modeled in software that is probably what would happen.
Using object oriented programming, someone would model me as a Developer class. But that class would have no idea how to go to an alumni get-together, because it has no concept of partying. So I would effectively have to be modeled by several classes, and then one would have to either have several instantiated objects with the having to implement all of these in one single class we instead use the notion of mixins to handle the implementation.
Composites
A mixin is implemented as a plain Java class, that typically implements a particular interface to be exposed by the Composite that it is a part of. The way we then declare a Composite is by creating a Java interface that through annotations declare what mixins to use, and by using the “extends” keyword describe what domain interfaces should be exposed. This gives us a central point that deterministically defines the structure and behaviour of the Composite.
With COP we suggest that while it is a good idea to keep cross-cutting concerns in separate implementation classes, the description of how these should be put together, or composed, is something that should be done centrally, in Java interfaces. In order to avoid duplication of such descriptions we use the “extends” keyword to reuse declarations in the extended interfaces. By modifying an extended interface such modifications will then automatically change the Composite interface declarations that extended it, so that we don’t have to modify each of them individually.
Figure: Composites are built from the fragments, Constraints, Concerns, SideEffects and Mixins. This diagram Method shows how those fragments are related to each other and each method invocation.
With this approach we believe that we get the best of both worlds: the separation of concerns in separate implementation classes, each dealing only with one specific task, and a centralized and deterministic declaration of what the final Composite should look like, thereby putting the developer of the Composite in charge of what should go into the definition of it and what should not be in there.
Code sample
So how would this work in practice? Well, let’s take me as an example. If I was a
Composite I could be described like this:
@Mixins({DeveloperMixin.class, SpeakerMixin.class, AlumniMixin.class}) public interface HumanComposite extends Developer, Speaker, Alumni, Composite {}
The extended interfaces would contain the actual methods to be invoked, and it is
up to the Qi4j runtime to construct a Composite instance that can route invocations
from clients to specific mixin instances. But it is important to note that from the
clients perspective this is just a regular Java object, even though it perhaps has more
interfaces than your usual domain object would have if it was implemented using
regular OOP. And the domain interfaces, such as Developer, are regular interfaces
with nothing specific to Qi4j, and the implementations themselves are also simply
Java classes that implement the interface. The identity of the object, however, is
defined by the Composite instance rather than the individual mixin instances, that
solves the identity crisis: a reference to “me”, as an object, can be sent around the
system and casted to the interface that is useful in that particular context. If more
domains and contexts are introduced, then the Composite can be extended to handle them too.
If we want to create another Composite that also uses the Alumni interface and
implementation, we can do so by having that interface extend Alumni as well, and
declare the same mixin to be used. The usual problems with multiple inheritance
and reuse of base classes is thereby avoided.
Summary
The goal set by OOP, that of modeling domain concepts through objects, has for a
long time been handled in insufficient ways. By introducing the idea that it is objects,
contexts, and interfaces that are important, rather than classes, Composite Oriented
Programming solves this and makes it radically easier to compose and reuse code.
We believe that this will have a very positive impact on the possibility to create
new and more sophisticated software without adding unnecessary complexity in the
process. Stay tuned for more details in the next JayView issue.
COP Composite Oriented Programming.
Composite The object equivalent in Composite Oriented Programming.
Mixin A Fragment in a Composite that contains state.
Fragment The parts that makes up a Composite. Mixins, Constraints, Concerns, SideEffects.
OOP Object Oriented Programming.
References
http://www.qi4j.org Main site.
http://www.qi4j.org/introduction.html Introduction material to Qi4j.
http://www.qi4j.org/145.html Composite Tutorial.
http://www.qi4j.org/17.html Participate in Qi4j development.
Originally published in JayView.