Mixins are the state-carrying part of a Composite instance. The other Fragments can not retain state between method invocations as they are shared across Composite instances.
The Mixin Type is the interface that declares the Mixin methods. Each Mixin implementation (the classes defined in the @Mixins annotation of a Composite declaration) implements one or more methods from one or more Mixin Types.Mixin Type can be very simple, like;
public interface BankAccount{ Money checkBalance();}
Or contain hundreds of methods, subclassed from dozens of super interfaces.The Mixin Types of a Composite are ;
- all the aggregated interfaces of the Composite Type, minus Composite meta-type interfaces, and
- all private mixin referenced types.
There is not a 1:1 correlation between Mixin Type and Mixin implementation. One can't even know if there are more or less of one over the other. That is because a Mixin implementation can implement less than one, one, or more than one Mixin Type.
Mixins are the state holders of the composite instance. Public Mixins are the mixins that are exposed to the outside world via the CompositeType interface.Each method in the CompositeType interface MUST be backed by a mixin class.
Mixins are declared as annotations on the CompositeType interface.
@Mixins( SomethingMixin.class )public interface SomethingComposite extends Something, Composite{}public class SomethingMixin
implements Something
{
// State is allowed.
public void doSomething()
{
// do stuff...
}
}
In the above sample, the SomethingMixin will be made part of the SomethingComposite CompositeType.If we have many interfaces defining many methods, that all must be backed by a mixin implementation, we simply list all the mixins required.
@Mixins( { StartMixin.class, VehicleMixin.class } )public interface CarComposite extends Startable, Vehicle, Composite{}public interface Startable
{
boolean start();
void stop();
}
public interface Vehicle
{
void turn( float angle );
void accelerate( float acceleration );
// more methods
}
In the example above, the VehicleMixin would need to deal with all methods defined in the Vehicle interface. That interface could be very large, and could be totally independent concerns. So, instead we should use abstract mixins, which are ordinary mixins but are lacking some methods. This is simply done by declaring the class abstract.
@( { StartMixin.class, SpeedMixin.class, CrashResultMixin.class } )public interface CarComposite extends Startable, Vehicle, Composite{}public interface Vehicle extends SpeedLocation, Crashable
{
}
public interface SpeedLocation
{
void turn( float angle );
void accelerate( float acceleration );
}
public abstract class SpeedMixin
implements SpeedLocation
{
// state for speed
public void accelerate( float acceleration )
{
// logic
}
}
Above the SpeedMixin only implements the accelerate() method, and Qi4j will only map that method to this mixin. The other method of the SpeedLocation interface is not satisfied as the example is written and will generate a runtime exception.Generic Mixins
There are also generic mixins, which are mixins that can handle any method type. This is done by letting the mixin implement the java.lang.reflect.InvocationHandler interface. For instance, let's say that we are not interested in the Location part of the above example, we simply provide a NoopMixin...
@( { StartMixin.class, SpeedMixin.class, CrashResultMixin.class, NoopMixin.class } )public interface CarComposite extends Startable, Vehicle, Composite{}public class NoopMixin
implements InvocationHandler
{
public Object invoke( Object proxy, Method method, Object[] args )
{
//return the right type depending on the method return type.
}
}
Luckily Qi4j provides a NoopMixin as part of the Qi4j API.
Public mixins expose their methods in the CompositeType, and this is not always desirable. Qi4j supports Private Mixins, which are only visible within the composite itself. That means that other fragments in the composite can see/use it, but it is not visible to the clients of the CompositeType.Private Mixins are handled automatically. When Qi4j detects a @This annotation referring to a type that is not defined in the Composite Type interface, then that is a Private Mixin. The Mixin implementation class, however, must exist in the list of Mixins in the @Mixins annotation. But often, the Private Mixin only list internal Property methods in the Mixin Type, which will be satisfied by the standard PropertyMixin and hence always available.
This is particularly useful in Domain Driven Design, where you only want to expose domain methods, which are defined by the context where they are used. But the state of the Mixin should not be exposed out at all. For instance, if we have the Cargo interface like;
public interface Cargo{ Location origin(); Location destination();
void changeDestination( Location newDestination );
}
The interface is defined by its context, and not really exposing the internal state. So in the implementation we probably do something like;
public class CargoMixin implements Cargo{ @This private CargoState state; public Location origin()
{
return state.origin().get();
}
public Location destination()
{
return state.destination().get();
}
public void changeDestination( Location newDestination )
{
state.destination().set( newDestination );
}
}
public interface CargoState
{
Property<Location> origin();
Property<Location> destination();
}
And the CargoComposite to bind it all together;
@Mixins( CargoMixin.class )public interface CargoComposite extends Cargo, EntityComposite{}
So, in this typical case, we don't need to declare the Mixin for the CargoState, as it only defines Property methods, which are handled by the standard PropertyMixin always present.