Search code examples
javascriptmodel-view-controllermultiple-inheritanceprototypal-inheritance

Multiple inheritance in Javascript with prototype chain


I have a JavaScript MVC design, implemented using prototypes, where different items may be displayed in different ways as decided by the controller. For example an 'Event' item may be displayed with the views ViewTabs or ViewSimple. Class hierarchy:

ViewBase
- ViewTabs 
-- EventViewTabs, which implements EventViewTabs.Validate
- ViewSimple
-- EventViewSimple, which implements EventViewSimple.Validate

Deciding whether to use EventViewTabs or EventViewSimple is done by a EventController. My problem is: I have a Validate method for checking inputs from the Event views, but this method is identical for the EventViewTabs and the EventViewSimple views. Where should I put Validate in order to avoid duplication? I cannot put it in ViewBase, as other items (e.g. User) also inherit from this class.

Seems I need multiple inheritance for this, but is there a smarter way to do it? I have a feeling I'm overlooking something obvious.


Solution

  • Basically your validator could be tailor-made with the type it has to work with. In UML, it's called composition. I figure out your code as follows:

    function Validator {}
    Validator.prototype.validate = function(arg) {
      //arg is no longer inputs
      return true|false; //the ultimate output along with additional information;
    }
    
    function EventViewTabsValidator() {}
    EventViewTabsValidator.prototype = Object.extend(Validator.prototype); //inheritance
    EventViewTabsValidator.prototype.constructor = EventViewTabsValidator; //enforce the constructor to point to your derived type
    EventViewTabsValidator.prototype.validate = function() {
      var inputs = $('inputs');
      var param = 'do some stuff specific to EventViewTabsValidator based on the inputs';
      return Validator.prototype.validate.call(this, param); //pass param, not inputs
    }
    
    function EventViewSimpleValidator() {} 
    EventViewSimpleValidator.prototype = Object.extend(Validator.prototype); //inheritance
    EventViewSimpleValidator.prototype.constructor = EventViewSimpleValdiator; //enforce the constructor to point to your derived type
    EventViewSimpleValidator.prototype.validate = function() {
      var inputs = $('inputs');
      var param = 'do some stuff specific to EventViewSimpleValidator based on the inputs';
      return Validator.prototype.validate.call(this, param); //pass param, not inputs
    }
    
    
    function EventViewTabs() {
      this.validator = null; //see init
    }
    EventViewTabs.prototype.init = function() {
      this.validator = new EventViewTabsValidator();
    }
    function EventViewSimple() {
      this.validator = null; //see init
    }
    EventViewSimple = function() {
      this.validator = new EventViewSimpleValidator();
    }
    

    Your could abstract up both types to a base EventView, which could expose this.validator. Your instance of EventController will call:

    var simple = new EventViewSimple();
    simple.validator.validate();
    
    var tabs = new EventViewTabs();
    tabs.validator.validate();
    

    Whatever the EventView instance, they implement their own specific validator that can be called in a generic way.