-
Notifications
You must be signed in to change notification settings - Fork 0
ReusingFragment
In this lesson we will learn how we can reuse a fragment instance in another morph kernel.
Let's suppose we will provide some serialization of the contact. This feature can again be expressed by means of a dimension trait:
@dimension
trait ContactSerializer {
def serializeContact: String
}
A simple JSON implementation can look like this:
@fragment
trait JsonContactSerializer extends ContactSerializer {
this: Contact =>
def serializeContact: String = {
s"""
{
'firstName': '$firstName',
'lastName': '$lastName',
'male': $male,
'nationality': '$nationality',
}
"""
}
}
We could now make a new morph using singleton
, however, it would create a new instance of Contact
and we would have to initialize its fields again. Instead, we are going to reuse the contact fragment, which has already been initialized in the previous lesson.
First, we have to pull the Contact
fragment instance from the original morph's kernel. The kernel of a morph is accessible through method kernel
.
val contactKernel = contact.kernel
One way to pull a fragment from a kernel is to invoke fragmentHolder
method on it, which looks for the fragment identified by the type argument and returns Option[F]
, where F
is the fragment type being searched for.
val contactFragInst = contact.kernel.fragmentHolder[Contact] match {
case None => sys.error("unexpected")
case Some(holder) => holder.proxy
}
Note: Although this procedure is quite straightforward, it unnecessarily handles the situation when the fragment is not found. It will be fixed in the future. There are other ways to extract a fragment type-safely by means of so called kernel references, which we will be dealing with later on. For the time being one may consult the source code of this lesson for the alternative approaches.
When Morpheus is creating a kernel from a morph type, it is looking for fragment factories for all fragments that occur in the morph type. The lookup mechanism is based on Scala implicit values. For every fragment type, the singleton
macro generates an implicit parameter, which is by default satisfied by an implicit macro supplying the singleton factory (creating a new instance of the fragment just once). This behavior can be overridden by declaring an implicit value holding a custom fragment factory. There is a couple of predefined fragment factory macros, but our needs fits best the external
macro, which creates a fragment factory producing an already existing fragment instance.
implicit val contactFragInst = external(contactFragment)
This declaration overrides the default fragment factory and the new kernel will be initialized with the factory delivering the existing contact fragment.
val contactSerialKernel = singleton[Contact with JsonContactSerializer]
We can verify that the contact state is reused by calling serialize
and printing its result.
val contactJson = contactSerialKernel.!.serializeContact
println(contactJson)
####Morpheus Tutorial####
- Modelling simple entity
- Adding some behavior
- Abstracting fragment
- Reusing fragment
- Using fragment in Java
- Multidimensional morphs
- Morphing strategies
- Mutable morphs
- Delegating and sharing
- Dimension wrappers
- Fragment wrappers
- Using a morph as a fragment
- Kernel references
- Kernel references use cases
- Promoting, masking and rating