Qi4j

Tutorial 9 - Private and abstract mixins

Now we're going to turn around and see how we can reduce the code needed to implement the HelloWorld example. We will also look at how to hide the Properties from the client code, since Properties are often considered to be implementation details that should not be exposed to clients.

The first thing we will do is remove the behaviour interface, and move the say() method to the TransientComposite type. This forces the mixin to implement the TransientComposite type, which would normally mean that it would have to implement all methods, including those found in the TransientComposite interface. However, since we are only really interested in implementing the say() method we will mark this by declaring that the Mixin "implements" the TransientComposite type, but is also "abstract". This, using pure Java semantics, makes it possible to avoid having to implement all methods. Qi4j will during the initialization phase detect that the Mixin only handles the say() method, and therefore only map it to that specific method. In order to instantiate the Mixin it will generate a subclass which implements the remaining methods in the TransientComposite type, as no-ops. These will never be called however, and is there purely for the purpose of being able to instantiate the Mixin. The Mixin is considered to be an Abstract Fragment.

To hide the state from the client we need to use what is called Private Mixins. A Private Mixin is any mixin that is referenced by another Mixin by using the @This injection, but which is not included in the TransientComposite type. As long as there is a Mixin implementation declared for the interface specified by the @This injection it will work, since Qi4j can know how to implement the interface. But since it is not extended by the TransientComposite type there is no way for a user of the TransientComposite to access it. That Mixin becomes an implementation detail. This can be used either for encapsulation purposes, or for referencing utility mixins that help the rest of the code implement some interface, but which itself should not be exposed.

Since the state is now hidden the initialization of the TransientComposite is a bit more tricky. Instead of just instantiating it you have to create a TransientBuilder first, then set the state using .prototypeFor(), and then call newInstance(). This ensures that the state can be set during construction, but not at any later point, other than through publicly exposed methods.

Steps for this tutorial:
  1. Move the say() method into the TransientComposite interface.
  2. Remove the behaviour interface.
  3. Remove the HelloWorldBehaviourMixin, create a HelloWorldMixin and let the HelloWorldMixin implement the TransientComposite directly.
  4. Mark the HelloWorldMixin as abstract and implement only the say() method.
  5. Remove the HelloWorldState from the TransientComposite "extends" declaration.
  6. Remove the GenericPropertyMixin. The Property methods will be implemented by the standard PropertyMixin declared in the TransientComposite interface instead.

Solution

If you have successfully completed the task, you should end up with the following artifacts;

HelloWorldComposite.javaexternal link
HelloWorldMixin.javaexternal link
HelloWorldState.javaexternal link


Qi4j and the Qi4j logo are trademarks of Richard Öberg, Niclas Hedhman and the members of the Qi4j Core Team. See Qi4j licensing for more information.
Powered by SiteVisionexternal link.