My favorites | English | Sign in

Google Desktop APIs (Labs)

Object-oriented Programming Principles in Desktop Gadgets

This article was written and submitted by an external developer. The Google Desktop Team thanks Teodor Filimon for his time and expertise.


Teodor Filimon, Gadget Developer
August 2007
"One for all, and all for one"  -  Alexandre Dumas, pere

Introduction

Object-oriented programming (OOP) is a programming paradigm that seeks to solve problems in terms of objects and their interactions. OOP helps you solve difficult problems by providing techniques to model real-life conditions in code. Also, it can improve the efficiency and readability of code.

Usually, when creating software this way, we draw up schemes that represent objects and the interactions among them. The convention most often used is the Unified Modeling Language (UML) which has become the standard for diagramming in OOP.

This article shows you how to discover possible objects in the problem domain and how to represent them. We will also see how to use OOP in JavaScript within the context of gadget development.

General OOP Principles

Object-oriented programming obviously deals with objects. To understand objects we first need to be aware of their type, which is described in something that's called a class. Objects are actually instances or tangible forms of a certain class.

Attributes and Methods

In OOP, a class typically contains attributes, methods, and a name to differentiate it from other classes.

  • attributes - represent properties of an object and can usually be accessed using a dot like this: anObject.someAttribute. It's important to know that an attribute can be of any type, even the type of the object that contains it.
  • methods - represent what an object can do, and are also accessed (executed) using dot notation: anObject.someMethod(parameters). You can differentiate them from attributes in this way: an attribute can only have a value or a state, while a method can do something or perform an action.
When defining attributes and methods, we also need to specify their visibility. The most important visibility operators are: public (accessible from the outside of an object) and private (invisible to the exterior and accessible only to the inner workings of the object). Private members usually are helpers or auxiliary to the computations needed in an object. Not all programming languages deal with or have a notion of visibility. For example, in JavaScript visibility cannot be specified; methods and attributes are all "public".

Constructors and Destructors

To create the object instances we've been talking about, we use special methods called constructors, which are responsible for creating and initializing a new object. They are usually named after the class they construct. In some languages, we can also define our own destructor methods.

//constructing the object, an instance of a class
objectInstance = new ObjectClass();

//the constructor can have parameters
salary = 1000000;
me = new Employee(salary);
You can find out how to create constructors and destructors in JavaScript later in this article.

In a Google Desktop gadget, you can take advantage of certain API events to construct and destroy objects in an organized manner. For example, if you have an object that will be used constantly throughout the lifetime of the gadget, you can create it in the view's onopen event and destroy it within the onclose event.

Basic OOP Principles

In the programming world, there has yet to be a standard definition of OOP that everyone will agree upon. What's important is that basic principles have been formulated to help us understand and use OOP:

  • modularity - it's probably the core part of OOP. We need to find individual entities in our program. In the end, they can be pretty much anything (objects, classes, etc.), but what's important is that we have to spot what can break away from the rest of the solution and code it separately. This may not always be observed by users of the final product, but it's vital to good code design. Not only does it make your code easier to visualize, but if you need to fix a bug or implement an update, you'll be able to find the right spot a lot faster.
  • Modularity
    Figure 1: Modularity

  • encapsulation - strongly connected to modularity. It says that everything except the interface of an object should be hidden, so that the actual implementation can easily be changed independently. As a bonus, this also improves program security. However, this implies that the interface (public attributes and methods) cannot change once it's published. Most of these ideas are nicely exemplified in Figure 2. We all know what that is, and that it stores data, but we don't actually see the data or how it's stored. We just see something that goes into the USB port — that's the interface. :)
  • USB Drive
    Figure 2: Encapsulation example

  • inheritance - is another fundamental concept of OOP and probably the reason why OOP works so well. Among other things, it allows us to establish patterns and save space when writing code by creating classes that inherit from another class. This means that the subclass has all the public fields of the superclass and can also add their own. A nice example is shown in Figure 3, which also introduces some UML symbols to represent inheritance.
  • Inheritance
    Figure 3: Inheritance

    There are a lot of vehicle types (we can say they inherit the class called Vehicle), but in Figure 3 we can see two examples: Bus and Racecar. They all inherit the superclass' public members, like numberOfPassangers or stop(), but they also define their own methods and attributes. For example, a Bus has a station schedule, and a Racecar has an activeGrandPrix to show us the track it's competing on this week.

  • polymorphism - is related to inheritance, and it's the thing that makes OOP so flexible. Basically, you can treat a derived class just like the parent, based on the fact that the derived class has at least everything the parent class has. Considering the situation above, if a person's job is to park cars when they arrive at a hotel, that person will probably use the ignition(), go(speed) and stop() methods, regardless of the kind of car.

Deeper Understanding

As I've said, when creating a program using OOP, some initial planning and design is usually performed before the actual implementation. A class diagram is basically a drawing that shows the program structure, specifically the relations between classes used in that program. To find out more about types of relations and class diagrams, you can go to the Class Diagrams section in the full version of this article.

If class diagrams are static representations that focus mainly on class attributes, sequence diagrams show the dynamic interaction between objects. To find out more, you can check out the Sequence Diagrams section from the full article.

How to Use OOP in a Gadget - Basic Concepts

Chart
Figure 4: What's behind that graph?

This section shows you how to bypass some common problems and how to create and use class-like entities.

How often have you had to make two arrays that have the same length, but refer to different properties of the same object? Well it's been too often for me. :) A more elegant solution involves OOP. For example, in my Chart gadget, I condensed two arrays into a single array, containing elements of a certain type. First, I created a class called Dot to hold the location of a point.

function Dot(xParam,yParam){
  this.x=xParam;
  this.y=yParam;
}

As you can see, the x and y attributes are set when calling the class constructor. You can see an actual call here:

function MakeArray(dataParam){
  //...
  aux=data.split(';');
  for (i=0;i<aux.length;i++) {
    coordinates=aux[i].split(',');
    dots[i]=new Dot(parseInt(coordinates[0],10),parseInt(coordinates[1],10));
  }
}

After I get the coordinate values, which are initially in a comma-separated string, I create a dots array containing Dot objects. Here's a snippet of code that calculates sizes and positions for the chart lines based on the previously recorded point coordinates.

for (i=0;i<dots.length-1;i++){
  lines[i]=chart.appendElement("<div height='2' background='#888888'/>");
  lines[i].x=(dots[i].x-minXValue)*xUnit+2;lines[i].y=height-(dots[i].y-minValue)*yUnit-2;
  lines[i].rotation=-Math.atan((dots[i+1].y-dots[i].y)*yUnit/(dots[i+1].x-dots[i].x)/xUnit)*180/3.1415;
  lines[i].width=Math.sqrt(sqr((dots[i+1].y-dots[i].y)*yUnit)+sqr((dots[i+1].x-dots[i].x)*xUnit));
}

Accessing the coordinate values is intuitive (dots[i].x and dots[i].y) and eliminates the need for two arrays. You should also note that the encapsulation which results from this relatively simple optimization is a huge help when debugging. :)

Advanced Implementations

Combobox Example

Combobox
Figure 5: Combobox created using OOP principles

The controls from the Google Desktop Gadget API (<button>, <img>, etc.) are object-oriented — they reflect all the principles detailed in previous sections of the article. I also made a control of my own having those principles in mind: a combobox. You can include it (freely) in your gadget simply by unzipping this archive into your build directory and including the script.

First, we have to figure out what the targeted behaviour will be. In the case of my combobox, I wanted to be able to do the following in the main.js file:

var a=new Array(3);
a[0]="element0";a[1]="element1";a[2]="element2";

function testClick(x){
  alert(c.getValue());
}

//creating the combobox
c=new ComboBox(view,50,50,200,3,"testClick",a);

//setting a value
c.setValue("element1");

//self-destruct after 20 seconds
setTimeOut("c=c.destroy();",20000);

Let's see what this snippet of code does. An array is created to have something to work with. After that, we define a function which we want to be launched when the onClick or onChange event is triggered. We then instantiate a combobox into the c variable using the constructor. Here is the definition of the ComboBox class:

function ComboBox(parent,x,y,width,numberOfDisplayedItems,onClickFunction,newArray){
  //some variables, not important for our example
  var CBbutton;var auxCBarray=new Array(); var actualNumberOfElements=0;var CBcontentDIV;var CBshape;

  //CONSTRUCTOR
  construct();
  function construct(){
    this.value="";
    //...
    //adding UI elements, calculating positions, etc.
  }
  
  //PUBLIC
  this.setValue=setValue;
  function setValue(s){
    this.value=s;CBedit.value=s;
  }

  //PUBLIC
  this.getValue=getValue;
  function getValue(){
    return (CBedit.value);
  }

  //PUBLIC (DESTRUCTOR)
  this.destroy=destroy;
  function destroy(){
    parent.removeElement(anotherReferenceToCBcontentDIV);
    parent.removeElement(anotherReferencetoCBedit);
    parent.removeElement(anotherReferencetoCBbutton);
    parent.removeElement(AnotherReferencetoCBShape);
    return null;
  }

  //...
}
First let's look at the prototype: ComboBox(parent,x,y,width,numberOfDisplayedItems,onClickFunction,newArray). Each parameter's meaning is pretty obvious - just notice the flexibility of the object due to the parent parameter. For example, if we want to create the combobox in a <div>, not directly in the <view>, we just enter the name of that <div> as the first parameter in the constructor.

We also have a setValue() method, a getValue() method, as well as a destructor function destroy(). Note that the destructor returns a null pointer. So if we have a reference named c, we can empty it like this: c=c.destroy();.

This code demonstrates how to simulate attributes and methods (using the object called this) and fully-functional constructors (by writing code in the actual function body). The methods can accept parameters and return values, just like normal functions.

Tips and Tricks

Here are some helpful tips about OOP in JavaScript:

  • You may have noticed in the snippets of code some comments said //PUBLIC. Those exist to make it easier for other developers to know what the visibility for every field is. Because JavaScript doesn't deal with visibility and all fields are public, we can use this convention: put an underscore in front of anything you would like to stay private, e.g. _privateFunction.
  • There are two ways to derive a class from another. One uses functions:

    function superClass() {
      this.f=superFunction;
    }
    
    function subClass() {
      this.inheritFrom = superClass;
      this.inheritFrom();
      this.f = subFunction;
    }

    ... and one uses the prototype attribute:

    function superClass() {
      this.f = superFunction;
    }
    
    function subClass() {
      this.f = subFunction;
    }
    
    subClass.prototype = new superClass;
  • Missing the instanceOf operator? This is included in other programming languages to help us discover and compare object types. You can write it yourself in JavaScript, again, based on the useful prototype:

    function instanceOf(object, constructorFunction) {
      while (object != null) {
        if (object == constructorFunction.prototype)
         {return true}
       object = object.__proto__;
      }
      return false;
    }
  • Here's how to check for an object's properties in JavaScript:

    function Dot(xParam,yParam){
      this.x=xParam;
      this.y=yParam;
    }
    
    d=new Dot(3,4);
    
    for (property in d)
      alert(property);

Conclusion

This might have been a long article, but we've gone through everything from basic OOP principles to practical uses. We have explored the potential of OOP through various examples and tricks. Object-oriented programming should be studied and exploited by every developer, and we've seen why gadget developers should not be an exception. :)

Many gadgets, everyone!

Resources


Author Bio

Teodor Filimon

I'm a natural born programmer. My first contact with a techno-gadget was Star Trek (remember those cool sensors?). I used to fill up a whole room with drawings of them when I was only 3 years old. Generally, I find a lot of inspiration for intuitive interfaces in things with "star" in their names (like Star Wars, Stargate,... :-) . I like the border between interface and function—it's the essence of a program, I think. Anyway, I'm a software engineering student now, and you can learn more about me and what I'm thinking and doing at my website or blog. My most popular gadgets are DigiWatch and TV Set.


Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License.