This is take 2 of the observable / plugin combination. The first post is here: http://www.sencha.com/forum/showthre...ponent-plugins

The idea is to have plain javascript objects easily support plugins. Just paste this html into a file in the root of your ext4 installation and you are good to go!

Code:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Ext.AbstractObject</title>
<link rel="stylesheet" type="text/css" href="resources/css/ext-all.css" />
<link rel="stylesheet" type="text/css" href="examples/shared/example.css" />
<script type="text/javascript" src="bootstrap.js"></script>
<script type="text/javascript">
var out;
Ext.onReady(function () {
  out = Ext.get("output");
});

function output ( msg ) {
  out.insertHtml("beforeEnd", msg + "<br>");
  // console.log(msg);
}

/**
 * @class Ext.AbstractObject
 * Shared base object class
 * <p>Base class for any object requiring events and plugin support.</p>
 * @constructor
 * @param {Ext.Element/String/Object} config The configuration options
 */
Ext.define("Ext.AbstractObject", {
  /**
   * @cfg {Object/Array} plugins
   * An object or array of objects that will provide custom functionality for this component.  The only
   * requirement for a valid plugin is that it contain an init method that accepts a reference of type Object.
   * When a component is created, if any plugins are available, the component will call the init method on each
   * plugin, passing a reference to itself.  Each plugin can then call methods or respond to events on the
   * component as needed to provide its functionality.
   */

  extend      : "Ext.util.Observable",
  constructor : function( config ) {
    config = config || {};

    this.callParent([config]);

    this.constructPlugins();
    this.initObject();
    this.initPlugins();
  },

  initObject : Ext.emptyFn,

  constructPlugins : function() {
    var me = this;

    if ( me.plugins ) {
      me.plugins = [].concat(me.plugins);
      for (i = 0, len = me.plugins.length; i < len; i++) {
        me.plugins[i] = me.constructPlugin(me.plugins[i]);
      }
    }
  },

  constructPlugin : function( plugin ) {
    if ( plugin.ptype && (typeof plugin.init != "function") ) {
      plugin.obj = this;
      plugin     = Ext.PluginMgr.create(plugin);
    }
    else if ( typeof plugin == "string" ) {
      plugin = Ext.PluginMgr.create({
        ptype : plugin,
        obj   : this
      });
    }

    return plugin;
  },

  initPlugins : function() {
    var me = this;

    if (me.plugins) {
        me.plugins = [].concat(me.plugins);
        for (i = 0, len = me.plugins.length; i < len; i++) {
            me.plugins[i] = me.initPlugin(me.plugins[i]);
        }
    }
  },

  initPlugin : function( plugin ) {
    plugin.init(this);
    return plugin;
  }
});

/* ------------------------------------------------------------ */
// Examples
/* ------------------------------------------------------------ */

// simple plugin
Ext.define("MyPlugin", {
  alias : "plugin.my-plugin",
  init  : function( obj ) {
    output(obj.$className + " MyPlugin constructor");
  }
});

// Three different ways to construct/init a plugin
// 1) ptype as a property in an object
// 2) init function as a property in an object
// 3) ptype as a string

// Use AbstractObject as a mixin
Ext.define("CanSing", {
  plugins    : [{ptype : "my-plugin"}],  // (1) ptype as a property in an object
  mixins     : {
    object   : "Ext.AbstractObject"
  },
  constructor : function ( config ) {
    output("CanSing constructor before AbstractObject");
    this.mixins.object.constructor.call(this, config);
    output("CanSing constructor after AbstractObject");
  },
  initObject : function () {
    output("CanSing initObject called from AbstractObject");
  }
});

// Use AbstractObject as a parent
Ext.define("Musician", {
  extend  : "Ext.AbstractObject",
  plugins : [
    {init : function () { output("Musician plugin.init") }}, // (2) init function as a property in an object
    "my-plugin"                                              // (3) ptype as a string
  ],

  constructor : function ( config ) {
    output("Musician constructor before AbstractObject");
    this.callParent([config]);  // construct AbstractObject
    output("Musician constructor after AbstractObject");
  },
  initObject : function () {
    output("Musician initObject called from AbstractObject");
  }
});

// Global so you can inspect in firebug
var sing, music;

Ext.onReady(function () {
  output("<b>About to construct CanSing</b>");
  sing = new CanSing({singing : true});

  output("<b>About to construct Musician</b>");
  music = new Musician({playing : true});
});

</script>

</head>
<body>
<h1>Ext.AbstractObject</h1>
<p>The example shows how to use the AbstractObject class.  Use firebug to see the code.</p>
<p id="output"></p>
</body>
</html>