-1

Edit: Removed higher-level ideas, included problem-specific and less-transferable code.

I implemented my DAL using DAO's. My application hooks in to various databases (mostly for legacy reasons). In order to facilitate efficient and intelligent usage of connections, I use a ConnectionBroker singleton to manage the various connections that may (or may not be) open. This ConnectionBroker is then injected into the DAO's where they can request control of a particular connection object, request new connections, ect.

From an inheritence POV, I'd like something like:

AbstractDbConnection
      |-- MongoDbConnection
      |-- MsSqlConnection
      |-- CouchDbConnection
      |-- ...

Where AbstractDbConnection defines an interface, and implements some shared event-based logic.

var EventEmitter = require('events').EventEmitter;

module.exports = function AbstractDbConnection(host, port, database, login, ...) {
    // private
    var state = StatesEnum.Closed; // StatesEnum = {Open: 0, Closed: 1, ..}; Object.freeze(StatesEnum);

    // api that must be overwritten
    this.connect = function connect() {throw new ...} 
    this.disconnect = function disconnect() {throw new ...}
    ... <more>
    this.getState = function() { return state; }
}
AbstractDbConnection.prototype.__proto__ = EventEmitter.prototype;

And then I implement the interface using driver-specific code:

var mssqldriver = require('mssqldriver'), //fictitious driver
    AbstractDbConnection = require(__dirname + '/blah/AbstractDbConnection');


module.exports = function MsSqlConnection(host, port, database, login, ...) {
    var me = this;
    // implement using driver
    this.connect = function connect() {...} 
    this.disconnect = function disconnect() {...}
    ... <more>
    driverSpecificConnection.on('driverSpecificOpenEvent', function() {
       me.emit('open'); // relay driver-specific events into common events
       state = StatesEnum.Open; // how ??
    }
    ...
}
MsSqlConnection.prototype.__proto__ = new AbstractDbConnection();

But clearly I want to protect the state property from changing inadvertently.

Colin
  • 1,835
  • 4
  • 24
  • 29
  • 3
    You need to demonstrate a knowledge of the problem being solved, and provide your attempts. And it seems like you want people to do your homework. – dezman Oct 09 '13 at 21:47
  • @watson I think the nature of the question implies that I understand the difficulty in applying this problem to a prototypical language. – Colin Oct 09 '13 at 21:52
  • @watson I don't see how this can read as 'homework'. It's a legitimate problem domain that isn't easily addressed due to the nature of prototypical inheritance. – Colin Oct 09 '13 at 22:04
  • @watson But I guess this is what I get for posting anything other than 'Javascript is the Best Language Ever!' with the `Javascript` tag.. – Colin Oct 09 '13 at 22:08
  • 2
    You need to show a specific problem, and your attempt(s) (in code) at solving it. As it is your question is too broad/vague. – dezman Oct 09 '13 at 22:10
  • 2
    Please, first learn to [do inheritance correctly](http://stackoverflow.com/q/10898786/1048572). My eyes hurt from reading `MsSqlConnection.prototype.__proto__ = new AbstractDbConnection();` – Bergi Oct 09 '13 at 23:37

2 Answers2

1

Just listen for the open event in the "abstract" constructor!

var EventEmitter = require('events').EventEmitter;
module.exports = AbstractDbConnection;
var StatesEnum = module.exports.StatesEnum = Object.freeze({
    Open: 0, Closed: 1, …
});

function AbstractDbConnection(host, port, database, login, …) {
    // private
    var state = StatesEnum.Closed;

    EventEmitter.call(this);

    this.getState = function() { return state; }
    this.on('open', function(e) {
        state = StatesEnum.Open;
    });
}
AbstractDbConnection.prototype = Object.create(EventEmitter.prototype);

// api that must be overwritten
AbstractDbConnection.prototype.connect = function connect() {throw new …};
AbstractDbConnection.prototype.disconnect = function disconnect() {throw new …};

var Mssqldriver = require('mssqldriver'), //fictitious driver
    AbstractDbConnection = require(__dirname + '/blah/AbstractDbConnection');
module.exports = MsSqlConnection;

function MsSqlConnection(host, port, database, login, …) {
    AbstractDbConnection.call(this);

    this.driver = new Mssqldriver(…);
    this.driver.on('driverSpecificOpenEvent', this.emit.bind(this, 'open'));
    …
}
MsSqlConnection.prototype = Object.create(AbstractDbConnection.prototype);
MsSqlConnection.prototype.connect = function connect() {…};
MsSqlConnection.prototype.disconnect = function disconnect() {…};
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks Bergi - this is actually a very clever idea. Bad day yesterday - thanks for being kind :) – Colin Oct 10 '13 at 16:15
0

You can use the module pattern to do this.

var transport_module = function() {
var mileage = 0; // private
return {
    transport : function(distance) {
    mileage += distance;
    }
  };
}

//use it
var car = transport_module(),
boat = transport_module(),
motorcycle = transport_module();


car.transport(10);
boat.transport(5);
motorcycle.transport(20);

The variable mileage is not visible to any other javascript code. Like a private java/C++ class variable. However, I would think about whether you need this kind of protection. I use modules a lot but not for small objects like class instances in java/C++.

Stephen O'Connor
  • 1,465
  • 1
  • 10
  • 20
  • Hmm perhaps I need to migrate my thinking away from the 'small object like classes' of tradOOP. My ultimate solution would have likely had separate constructors for a **car**, **boat**, and **motorcycle**. Perhaps this is best handled by a factory? – Colin Oct 09 '13 at 22:17
  • I think you can achieve what you are trying to do in terms of logic, services and properties with javascript, but the "formality" of C++ for example is hard to achieve. I always liked the use of "const" in C++ to reinforce meaning at the compiler level. You can't get that in javascript, but the upside in flexibility is worth it. – Stephen O'Connor Oct 09 '13 at 22:36