Decorating our objects in memory

We've seen examples where we modify the working memory whenever we detect that a specific condition is happening. We might remove objects, modify existing ones, and even delete them to trigger other rule executions. We've also seen that, sometimes, these elements make sense mostly within the rule executions and used declared types for these cases.

Whether we use declared types of external classes, most of the cases imply one of the following two strategies:

  • We add new objects (declared types or Java classes) to the working memory, representing some inference about our domain model
  • We modify attributes of existing objects in the working memory, adding the inferred data to these properties

These strategies have a few disadvantages when it comes to decorating an existing model. The first case (adding new objects) might imply having to keep a reference between the domain model object and the new inferred object in some form. The second case (modifying attributes) might imply modifying the domain model when we might not wish to do so.

There is a third alternative to these strategies, which implies adding a new nature to already existing objects without having to create extra attributes in the original beans. This dynamic decoration of existing objects in the working memory is known as traits.

Traits are like adjectives from an object-oriented perspective. We can say a house is pretty or a car is pretty. Adjectives can apply to many different types. However, these types don't need to share a common structure. This means that traits act like a flag that we can apply to multiple types and have specific attributes that apply to the adjective itself, and therefore, to the beans that apply the trait.

To explain this in a simpler way, think of traits as extra characteristics that we can dynamically add to certain objects in the working memory. We can filter these objects using these characteristics later in other rules. To do so, we need to do the following two things:

  • Define a trait: We can do this using Java classes, marking them with the @Trait annotation at class level, or with declared types such as the following:
          declare trait KidFriendlykidsAppeal: String
          end
  • Mark the classes and declared types that will have the trait applied with the @Traitable annotation.

Once we follow these steps, we can define the rules that apply the trait to the traitable objects. Let's consider an example based on our eShop case. Consider that we want to start classifying specific elements as kid-friendly in order to add advertising to them based on an age tier.

We can have items that are kid friendly, such as colored paper, toys, or special clothes. We might also have kid-friendly providers (they provide us with a lot of school-related items) or kid-friendly sales channels (such as parent-based sites where our eShop placed offers). If it wasn't for this qualification as kid-friendly, these elements wouldn't have any common structure. This is a good situation to apply traits.

Before we start using these traits, we need to see how to apply traits to our objects. To do so, we'll see the syntax of the don keyword.

Adding traits with the don keyword

Whenever we have an object where we want to apply a trait, we can do so using the don keyword. It receives the traitable object first, the trait type second, and an optional third boolean parameter to decide whether it should be logically inserted in the working memory. It returns an object casted to the type of the trait. Let's see the following example of its use:

rule "toy items are kid friendly"
       no-loop
       when $i: TraitableItem(name contains "toy")
       then
           KidFriendly kf = don($i, KidFriendly.class);
           kf.setKidAppeal("can play with it");
   end

The previous rule defines the conditions where we would consider a TraitableItem object (an object similar to Item, except it is annotated with @Traitable) as being kid-friendly. The reason for the no loop attribute on the rule is that don is not creating a new element, it is only decorating an existing one in the working memory. As this decoration doesn't make the object stop fulfilling the rule condition, the no loop avoids re-evaluations.

After using the don keyword, we will be able to treat this object as a kid-friendly object in any other rule. This means that rules that filter objects by the KidFriendly type can treat the traited object as a KidFr iendly element.

Removing traits with the shed keyword

If, at some point, after applying a trait to an object, we decide that this trait needs to be removed, we can do so with the shed keyword. Shed will cause the deletion of the trait corresponding to the given argument type, as follows:

Object o = shed( $traitedObject, KidFriendly.class)

This syntax, and the use you can give to the traits, is also exemplified in TraitTest of the code base.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.156.107