MPS 2019.1 Help

Builders

Builders allow users to construct objects and object hierarchies in a more convenient way. Instead of a manual instantiation of each and every object in the hierarchy and setting its properties one-by-one, with a dedicated builder the same data structure can be created in a more concise and intuitive way.

As an example, let's assume we're building a house.

House h = new House(); h.houseType = HouseType.detached; Address address = new Address(); address.street = "Na Lysinach"; address.number = "10"; address.city = "Prague"; address.zipCode = "23459"; h.locate(address); list<Room> rooms = new arraylist<Room>(0); rooms.add(new Room("livingroom", 25)); rooms.add(new Room("kitchen", 18)); rooms.add(new Room("bedroom", 20)); rooms.add(new Room("hall", 12)); rooms.add(new Room("bedroom", 15)); h.rooms = rooms; h.moveIn(6); println(h);

A house needs an address, which itself consists of several items, a bunch of rooms in it, each of which needs a couple of properties, and so on.

Instead of the cumbersome way, builders give you a syntaxtic shortcut to take:

 House house = new house { inhabitants : 6; type : HouseType.detached; address { street : "Na Lysinach"; number : "10"; city : "Prague"; zipCode : "23459"; } room { name : "livingroom"; size : 25; } room { name : "kitchen"; size : 18; } room { name : "bedroom"; size : 20; } room { name : "hall"; size : 12; } room("bedroom", 15) };

Looking at the code you can quickly grasp the structure of the created object graph, since the structure of the code itself mirrors the dependencies among created objects. Builders are nested into one another and they can hold properties. Both the property values and mutual nesting of builders is then transformed into the object hierarchy built behind the scenes.

Building Builders

To build your own builder, you first need to invoke New -> j.m.baseLanguage.builders.SimpleBuilders. Now you define builders for each object type that participates in the hierarchy. These builders hold their own properties and children, out of which they build the requested data structure. To stick to our earlier "House building" example, check out the sample below:

builders houseBuilders extends <no extendsBuilder> { root builder house() extends <no extends> { type: House create: new House() child address { attach parent.locate(child); } child room { attach parent.rooms.add(child); } property inhabitants : int { set parent.moveIn(value); } property type : HouseType { set parent.houseType = value; } } builder address() extends <no extends> { type: Address create: new Address() <<children>> property street : string { set parent.street = value; } property number : string { set parent.number = value; } property city : string { set parent.city = value; } property zipCode : string { set parent.zipCode = value; } } builder room() extends <no extends> { type: Room create: new Room() <<children>> property name : string { set parent.name = value; } property size : int { set parent.size = value; } }   builder room(string name, int size) extends <no extends> { type: Room create: new Room(name, size) <<children>> <<properties>> } }

We defined a builder for the Room class as well as for the Address class and also a root builder for the House class. Root builders, unlike plain builders, can be used directly in user code after the new keyword. Notice also that we have two builders for the Room class. The first definition allows properties to be nested inside the room block, while the second allows the two properties to come directly as parameters to the room method call. Both approaches can certainly be combined in a single builder.

The House, Room and Address classes in our case are ordinary classes with methods and properties. The methods as well as setters for the properties manipulated in builders must be visible to the builders. The "package" visibility will do in typical cases. To give you an example, see below the House class definition from our example.

  public class House extends <none> implements <none> { <<static fields>> <<static initializer>> private Address address; private int numberOFPeople; public HouseType houseType {get; <no visibility> set;} public list<Room> rooms {get; <no visibility> set;} <<initializer>> public House() { <no statements> } public void moveIn(int people) { this.numberOFPeople = people; } public void locate(Address address) { this.address = address; } public int numberOfInhabitants() { return this.numberOFPeople; } public String toString() { return "House for " + numberOFPeople + " people at " + address.?toString(); } <<static methods>> <<nested classifiers>> }
Last modified: 12 April 2019