Interfaces allow Java developers to define an Application Programmer
Interface (API) expressing the contract between a class and the
users of a class.
While JavaScript will not perform the type checking that interfaces
in Java provide, it does provide the basic tools necessary to
perform what is known as duck typing, the notion that if
it walks like a duck an quacks like a duck, for our purpose we
can assume it is a duck. JavaScript provides a way to determine
if an object has a property. The following code would determine
if the object o
is a duck.
if ( o.walk && o.quack ) {
// Congratulations! It's a duck!
}
To be thorough, we should test to see if walk and swim are both
functions. That is readily accomplished using the typeof
operator.
if ( o.walk && typeof(o.walk) == "function" &&
o.swim && typeof(o.quack) == "function") {
// Still a duck!
}
This approach to type checking has several problems. Performing these tests each time we need to know if an object implements a specific interface is not convenient and prone to errors, especially when the interface is complicated or the tests are performed frequently. It does not help us verify that an object implements interfaces that have no methods, such as the Serializable interface in Java. We would prefer to be able to document that a class implements an interface and verify that all methods of the interface are implemented.
To add support for interfaces in our framework, we will provide a way to declare an interface. Here is an example of the interface declaration syntax.
xclass.declareInterface("animal.Swimmer", [ "swim" ]);
We model an interface by creating the XInterface class which stores the name and namespace of an interface and a list of the interface methods.
function XInterface(className, namespace, methods) {
this.className = className;
this.namespace = namespace;
this.methods = methods;
}
XClass is augmented with a declareInterface
method
for declaring new interfaces. It maps the fully qualified interface
name to a simple name and namespace, creates an instance of
XInterface, and stores the new interface in the namespace.
declareInterface: function(fullName, methods) {
var names = fullName.split('.');
var name = names.pop();
var namespace = this.namespace(names);
var newInterface = new XInterface(name, namespace, methods);
namespace[name] = newInterface;
},
Next we will augment the framework with a way to add interfaces to classes.