| /////////////////////////////////////////////////////////////// |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| /////////////////////////////////////////////////////////////// |
| |
| [[tut-composites-step9,Step 9 - Private and Abstract Mixins]] |
| = Step 9 - Private and Abstract Mixins = |
| |
| Previous step was <<tut-composites-step8>>. |
| |
| 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. Zestâ„¢ 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 |
| Zestâ„¢ 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: |
| |
| - Move the say() method into the TransientComposite interface. |
| - Remove the behaviour interface. |
| - Remove the HelloWorldBehaviourMixin, create a HelloWorldMixin and let the HelloWorldMixin implement the TransientComposite directly. |
| - Mark the HelloWorldMixin as abstract and implement only the say() method. |
| - Remove the HelloWorldState from the TransientComposite "extends" declaration. |
| - 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 only; |
| |
| *HelloWorldComposite.java* |
| [snippet,java] |
| ---- |
| source=tutorials/composites/src/main/java/org/qi4j/tutorials/composites/tutorial10/HelloWorldComposite.java |
| tag=solution |
| ---- |
| |
| *HelloWorldMixin.java* |
| [snippet,java] |
| ---- |
| source=tutorials/composites/src/main/java/org/qi4j/tutorials/composites/tutorial10/HelloWorldMixin.java |
| tag=solution |
| ---- |
| |
| *HelloWorldState.java* |
| [snippet,java] |
| ---- |
| source=tutorials/composites/src/main/java/org/qi4j/tutorials/composites/tutorial10/HelloWorldState.java |
| tag=solution |
| ---- |