... | ... | @@ -27,103 +27,4 @@ All java packages of the TULIP framework share the common root package **lu.list |
|
|
|
|
|
At this point, it is important to mention that the majority of high-level building blocks of the TULIP framework are build using a variation of the **Builder** design pattern. The deviation from the original Builder design pattern consists in the fact that TULIP Builder objects no longer are required to implement a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface), allowing setting individual properties through chaining of setter methods. Loosening of this constrained was possible through the widespread use of XML bootstrapping for setting object properties, i.e. the properties of the individual builder objects are automatically retrieved from an XML scenario file, thus rendering a programmatic interface more or less obsolete. We're going to have a look at XML bootstrapping in the dedicated [Bootstrapping Section](bootstrapping).
|
|
|
|
|
|
### Widgets
|
|
|
|
|
|
Throughout the entire TULIP framework, **Widgets** are to be located in the **lu.list.itis.dkd.tui.widget** package. As already stated in the [Basics](basics) section, widgets implement the functional behaviour of the physical object they represent. The root java class of all Widgets is the **BaseWidget** class. Another convention used throughout the entire TULIP framework is that each Widget requires a pair of Builder objects which MUST be located inside the **lu.list.itis.dkd.tui.widget.builder** package. They also need to follow a given naming convention since TULIP is using [Reflection](https://www.oracle.com/technical-resources/articles/java/javareflection.html) to locate and instantiate the respective builder classes.
|
|
|
|
|
|
#### Builders
|
|
|
|
|
|
As already mentioned earlier, every Widget that can be instantiated requires a pair of Builder objects. The actual workhorse in the widget building process is the **BaseBuilder** class. The **BaseBuilder** builder class is an abstract class, i.e. it can not be instantiated, which implements the actual property retrieval from the XML scenario. We'd like to introduce a number of core concepts common to all BaseBuilder classes.
|
|
|
|
|
|
##### BaseBuilders
|
|
|
###### Declaration
|
|
|
|
|
|
All BaseBuilder class are to be defined as *abstract* and should follow the following declaration convention.
|
|
|
|
|
|
> public abstract class BaseSomeWidgetBuilder<B extends BaseSomeWidgetBuilder<B>> extends BaseBuilder<B>>
|
|
|
|
|
|
The **BaseBuilder** class, which is the root class that all BaseBuilder classes inherit from is declared in a s similar way.
|
|
|
|
|
|
> public abstract class BaseBuilder<B extends BaseBuilder<B>>
|
|
|
|
|
|
What does this mean exactly? Lets start with the declaration of the root BaseBuilder class itself. The class is declared as a generic template class, declaring a generic Type B which is a subclass of BaseBuilder itself. The correct terminology for this is *Upper Bounded Generics*, meaning the generic argument on the left-hand **B** side is assumed to be exactly the generic argument on the right-hand side of the assignment.
|
|
|
|
|
|
###### Properties
|
|
|
|
|
|
BaseBuilder class MUST expose all properties retrieved from the XML scenario file as public fields. At first sight, this appears to break the general object oriented paradigm of encapsulation, which it does. It is important to note though, that Builder objects are short lived and will only be used in the actual built objects constructor, thus, the risk of potential side effects caused by direct exposure of the instance fields is acceptable.
|
|
|
|
|
|
>// The name that will be given to the widget.
|
|
|
>
|
|
|
>**public** String name;
|
|
|
>
|
|
|
>// The (optional) Id of the stage to present the widget.
|
|
|
>
|
|
|
>**public** int stageId;
|
|
|
>
|
|
|
>// Specifies whether this widget is an avatar for a tangible object or not.
|
|
|
>
|
|
|
>**public** boolean tangible;
|
|
|
>
|
|
|
>// The visual components making up the visual representation of the widget
|
|
|
>
|
|
|
>**public** Multimap<Integer, Corona> coronas;
|
|
|
>
|
|
|
>//The base where the widget is at.
|
|
|
>
|
|
|
>**public** HashMap<Integer, Point> positions;
|
|
|
|
|
|
###### Constructors
|
|
|
|
|
|
BaseBuilder class MUST implement two constructors with the following signature
|
|
|
|
|
|
> public BaseBuilder(Element rootElement) throws BuildException
|
|
|
>
|
|
|
> public BaseBuilder(Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException
|
|
|
|
|
|
Both constructors require a XML Node (org.jdom2.Element) parameter called **rootElement**. This is the node in the XML scenario to retrieve the properties for the widget to be build from. The two additional parameters for the second constructor allow the widget to be built from **object templates**. Object templates allow the declaration of re-usable widget definitions by using variables. Values for those variables are passed in the **context** parameter during construction time. Object templates will be discussed in more detail in the dedicated [Templates](bootstrapping/templates) section.
|
|
|
|
|
|
###### build() Method
|
|
|
|
|
|
BaseBuilder objects MUST define a build() method returning an instance of the widget to be build. For instance, the BaseSomeWidgetBuilder builder class we defined earlier in this section shall define a build method with the following signature
|
|
|
|
|
|
> public abstract SomeWidget build();
|
|
|
|
|
|
In a nutshell, that's all it takes to define a BaseBuilder class. As already mentioned earlier, BaseBuilder classes are abstract and thus can't be instantiated. But how do we get an actual instance? That's where their sibling, the actual **Builder** class comes in.
|
|
|
|
|
|
##### Builders
|
|
|
###### Declaration
|
|
|
|
|
|
All Builder class are to be defined as *final* and should follow the following declaration convention.
|
|
|
|
|
|
> public final class SomeWidgetBuilder extends BaseSomeWidgetBuilder\<SomeWidgetBuilder\>
|
|
|
|
|
|
We have to define them as final to make sure they can't be extended. Even though doing otherwise wouldn't hurt, we want to restrict inheritance at BaseBuilder level. Builder class are mere factory classes to build the actual widget.
|
|
|
|
|
|
###### Constructors
|
|
|
|
|
|
Builder class MUST implement two constructors with the same signature as those of their parent class
|
|
|
|
|
|
> public SomeWidgetBuilder (Element rootElement) throws BuildException
|
|
|
>
|
|
|
> public SomeWidgetBuilder (Element rootElement, BootstrapContext context, BootstrapCallback callback) throws BuildException
|
|
|
|
|
|
Those constructors basically only call their super constructor.
|
|
|
|
|
|
###### build() Method
|
|
|
|
|
|
The build method of the Builder class has to implement the build method previously declared in the BaseBuilder class. As a consequence, it has the same signature and return type.
|
|
|
|
|
|
> public SomeWidget build() {
|
|
|
>
|
|
|
> return new SomeWidget(this);
|
|
|
>
|
|
|
> }
|
|
|
|
|
|
As you can see, implementation is limited to instantiating a new Widget of the given class, passing the Builder object as only parameter. The Widgets constructor will then use the Builder's inherited public fields to initialise its own private properties.
|
|
|
|
|
|
### Coronas
|
|
|
|
|
|
Throughout the entire TULIP framework, **Coronas** are to be located in the **lu.list.itis.dkd.tui.widget.corona** package. As already stated in the [Basics](/nui/tulip/-/wikis/basics) section, coronas implement the visual representation of the physical object they represent. The root java class of all Coronas is the **Corona** class.
|
|
|
Just like the widgets, each Corona requires a pair of Builder objects which MUST be located inside the **lu.list.itis.dkd.tui.widget.corona.builder** package. CoronaBuilders follow the same conventions and guidelines as Widget builders.
|
|
|
|
|
|
|
|
|
\ No newline at end of file |