
This is an object-oriented Servoy tutorial on how to use inheritance patterns in Servoy. I use objects a lot, so I thought it would be a good idea to introduce you to a few basic inheritance patterns and how to use them with Servoy. If you have not yet read my article on “Object-Oriented Programming” in Servoy, you should read that first, as it is the foundation that this article builds upon. You will find the link in the “Related Posts” at the end of this article.
For our purposes, inheritance can be thought of as new objects that inherit the properties and methods of an initial object that is returned by a constructor.
Below are the three most common patterns for creating new objects using a constructor. The conventional patterns have been modified to accommodate Servoy’s unique needs, which handles JavaScript files differently from a conventional browser.
1. Prototype Pattern
The prototype pattern consists of two main parts; a constructor and a prototype. The constructor contains the properties that will be unique for each new object created using the constructor. The prototype can contain properties and functions (methods) that will be shared among all objects created using the constructor; only one copy exists in memory. In other words, the properties and functions are defined once per prototype, and are shared among all the objects created with the constructor.
The first step is to define the constructor and put all the properties into it that need to hold unique values for each occurrence of a new object. We define the properties by using the JavaScript this keyword, and assign the parameters passed to the constructor as the property values. In our example, we are building a fruit constructor, and the unique properties for each fruit object will be things like type of fruit, color of fruit, rating and price. We will be able to pass in parameters to this constructor and get back a new fruit object with specific properties values, like those of an orange or apple.
// Create the basic object function Fruit1(name, color, rating, price) { this.name = name; this.color = color; this.rating = rating; this.price = price; }
The next step is to create the prototype, adding the additional properties and functions that will be shared among all the objects created with the constructor. Any references by functions to properties defined in the constructor must use the JavaScript this keyword. The functions in the prototype go in the object literal, but are written so that the name of the function is like a property. In our example, we have defined two functions on the fruit prototype, each of which access properties in the constructor and return a concatenated string.
For Servoy to see the prototype, we need to define the prototype inside of an immediately invoked function, and assign it to a variable. When Servoy reads this JavaScript file, it will see the immediately invoked function, execute it, and assign the prototype into memory. That’s all we have to do to get Servoy to recognize the prototype.
//Adding to the protoype chain var foo1 = function(){ Fruit1.prototype = { type: function () { return 'I am a ' + this.color + ' ' + this.name; }, getInfo: function(){ return 'Rating: ' + this.rating + ', Price: ' + this.price } }; }();
The final step is then to create a new object using the constructor by passing in the parameters that define our piece of fruit. The constructor creates the object, sets the properties of the object created to the values of the parameters we passed in, and returns to us the object with the prototype already attached. We can then reference the properties in the new object using the object.property syntax, or call a method on the prototype using the object.method() syntax.
// Normal prototype pattern var oApple = new Fruit1('Apple', 'Red', 5, 0.10); application.output("Name: " + oApple.name); // Name: Apple application.output("Type of Fruit: " + oApple.type()); // Type of Fruit: I am a Red Apple application.output("Details: " + oApple.getInfo()); // Details: Rating: 5, Price: 0.1
Its important to realize that you can override properties and methods by re-defining them on the object you created with the constructor. Objects are mutable, so you can change them at any time.
The prototype pattern works quite well in Servoy, and is highly efficient, but its not the only game in town.
2. Revealing Module Pattern
The revealing module pattern is one of my favorites, because it is quite compact, and has less reliance on the JavaScript this keyword. It does not separate the constructor and the prototype, and hence it creates a unique instance of all the properties and functions for each object created with the constructor. Although it is not as memory efficient as the other two patterns discussed here, it is ideally suited for instances when only a small number of objects will be created from the constructor.
//Revealing module pattern function Fruit2(name, color, rating, price) { var _name = name, _color = color, _rating = rating, _price = price, type = function () { return 'I am a ' + _color + ' ' + _name; }, getInfo = function(){ return 'Rating: ' + _rating + ', Price: ' + _price }; return { type: type, getInfo: getInfo }; }
What this pattern really does is it allows you to make certain properties and functions private, and only reveal public methods, like an api. Only the properties and functions specified in the return object will be public, all other inner workings of the object are hidden and not accessible externally. In our example, you can see that only the two functions are public and exposed to external access. Attempting to reference one of the private properties will result in “undefined”.
// Revealing module pattern (Works) var oApple = new Fruit2('Apple', 'Red', 5, 0.10); application.output("Name: " + oApple.name); // Name: undefined application.output("Type of Fruit: " + oApple.type()); // Type of Fruit: I am a Red Apple application.output("Details: " + oApple.getInfo()); // Details: Rating: 5, price: 0.1
The revealing module patterns works extremely well with Servoy and is perfect for when you are creating a small number of objects and you want to restrict what properties and functions are available externally, like in an api.
3. Revealing Prototype Pattern
The revealing prototype pattern combines the two patterns we have examined so far. It allows us to have private and public properties and functions, as well as being highly efficient by using the prototype to share a single copy of the functions among all object created with the constructor. This is the trickiest pattern to do in Servoy, so pay close attention.
The first step is again to define the constructor. As before, it will accept the parameters and set the properties using the JavaScript this keyword. All the properties in the constructor are public and are accessible.
// Basic constructor function Fruit3(name, color, rating, price) { this.name = name; this.color = color; this.rating = rating; this.price = price; }
The next step is to define the prototype. In Servoy, we have to do this using an immediately invoked function that is assigned to the prototype, that is in turn assigned to a variable. This allows Servoy to see the variable, assign the function to the prototype, execute the function, and store the prototype into memory as the prototype of the constructor. Whew, pretty complicated, right?
// Add methods to the prototype chain var foo4 = Fruit3.prototype = function() { // Private (could have more private methods) var type = function () { return 'I am a ' + this.color + ' ' + this.name; }, getInfo = function(){ return 'Rating: ' + this.rating + ', Price: ' + this.price }; // Public members return { type: type, getInfo: getInfo }; }();
Like with the revealing module pattern discussed earlier, properties and functions can be defined in the prototype and will remain private. Only the members you choose to include as public member in the return will be excisable. All your other properties and methods that make-up the internal workings of your code are never exposed, but you still have everything in one place for easy maintenance and scalability.
// Revealing prototype pattern (Does not work) var oApple = new Fruit3('Apple', 'Red', 5, 0.10); application.output("Name: " + oApple.name); // Name: Apple application.output("Type of Fruit: " + oApple.type()); // Type of Fruit: I am a Red Apple application.output("Details: " + oApple.getInfo()); // Details: Rating: 5, price: 0.1
As you can see, these patterns can easily be used for object-oriented programming in Servoy. They offer many advantages over conventional “function spaghetti code” programming that can quickly become confusing, difficult to maintain, and extend. Objects offer enormous power; build once and use again and again. They are mutable and can easily be changed to suit unique variations, and they are very easy to work with. All your code is in one place, easy to maintain, easy to extend, and elegant.
What are you waiting for? Crank-up that Servoy Developer and start using OOP in your code today.