Medryx Observations

June 7, 2008

Javascript, OOP, and Abstract Classes

Filed under: javascript, oop — Tags: , — maulin @ 6:15 am

One thing that is clearly missing from javascript is a clear way to distinguish private and public methods within a class. Convention dictates that methods and properties beginning with an underscore are “private”, and others are “public”. And this works fairly well.

But recently, I have been building a very complicated web application, and I have really started to miss abstract classes, interfaces, and protected methods. Dojo has addressed many of these issues with its dojo.declare() syntax. With it, you can mixin an interface, or a base class when creating a new class (or more than one for that matter).

But there still isn’t any real support for abstract classes and abstract methods. As you know, abstract methods must be implemented by subclasses. In addition, there is no support for protected methods. if underscore is private, and no underscore is public, what is a protected method that should only be called or implemented by subclasses?

First, we need to decide how to indicate a method is abstract/protected. I’ve decided a reasonable approach is to prefix the method name with a $. Its unobtrusive, valid javascript, and is far prettier than “protected_” or something like that.

So now we have a way to mark methods that are required to be implemented in a subclass. For example:

dojo.declare("medryx.dao.AbstractDao", medryx.AbstractBase, {
   /**
    * abstract - the entity managed by this dao
    */
   $getEntityClass:null,
 
   /**
    *abstract - the smd of a service that is used by this dao
    */
   $getService:null
});

Notice that these abstract methods are prefixed with “$”, and assigned to null. This is key. The subclasses should implement them as methods as:

dojo.declare("medryx.dao.TeamsDao", medryx.dao.AbstractDao, {
   $getEntityClass:function() {
      return medryx.model.Team;
   },
   $getService:function() {
      return medryx.rpc.TeamService;
   }
})

Now obviusly, we could just stop there, and adhere to this convention. But errors that are borne out of not implementing these methods can be hard to find, or come out quite late… only after trying to use these methods. To address this problem I have built a base abstract class that any abstract class can inherit from (or mixin). This AbstractBase class will check the class in its constructor, and be sure all $ methods have been implemented. If they haven’t, it will throw an exception — in the constructor. Which of course means that the moment you instantiate the class, the error will occur, and will be quite descriptive of the problem. Its not quite as good as “compile-time” checking, but its closer.

Here is the code:

dojo.provide("medryx.AbstractBase");
dojo.require("medryx.exceptions.UnimplementedAbstractMethodException");
dojo.declare("medryx.AbstractBase", null, {
   constructor:function(args) {
      for (var methodName in this) {
         if (methodName.charAt(0) === '$') {
            if (!dojo.isFunction(this[methodName])) {
               throw new medryx.exceptions.UnimplementedAbstractMethodException(methodName);
            }
         }
      }
   }
});

So what are your thoughts? I think the runtime overhead of this is likely to be fairly small. But honestly, this is mostly code you need at development time. You could conceivably completely remove this constructor for production code, since presumably you have ferreted out bugs like this long before production. Heck, it could even be part of your build script!

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress