1

I have a hierarchy of classes, and I'd like that each object had an ID of the form Classname-integer (examples: Car-0, Car-1, Motorcycle-0, Truck-0, Truck-1, ...)

The class hierarchy is

Vehicle
   Car
   Motorcycle
   Truck

The problem is: I want to write just once the code that manages IDs and I'm lost in costructors, prototypes, late binding, and so on.

Example of what I'd like to obtain in pseudocode:

car = new Car
anotherCar = new Car
car.id                  // "Car-0"
anotherCar.id           // "Car-1"
truck = new Truck
truck.id                // "Truck-0"

the Car constructor initializes the object id with the current Car available id, and then increments it so that the next new Car will have a different id. This must not affect other classes IDs.

Ideally, I'd like to write the code just in the base class Vehicle, but I don't know if it is possible.

My current target language is Coffeescript / Javascript but other languages are welcome along with some reasoning on how it works.

How would you solve this?

Giacomo
  • 11,087
  • 5
  • 25
  • 25
  • The answers to http://stackoverflow.com/questions/1535631/static-variables-in-javascript might help. – chelmertz Sep 20 '11 at 14:19
  • Well, it's possible in Python, but only using a - albeit simple - metaclass (at least I think so for now). –  Sep 20 '11 at 14:20
  • Technically seen ECMAScript (JavaScript) doesn't have classes, just constructor functions that bind data to an object. – Aidiakapi Sep 20 '11 at 14:20

4 Answers4

2

You can use the Vehicle constructor to add a prototype function that will update the ID, like this: http://jsfiddle.net/ZDUEk/.

(function() {
    var ids = {}; // remember last id

    function Vehicle() {

    }

    Vehicle.prototype.applyVars = function() {
        var name = this.constructor.name, // Car or Truck
            id   = ids[name];

        if(!id) {
            id = ids[name] = 0; // init id
        }

        this.id = name + "-" + id; // set to form Type-X

        ids[name]++; // increment for next id
    };

    function Car() {
        this.applyVars(); // set id
    }

    function Truck() {
        this.applyVars(); // set id
    }

    Car.prototype = new Vehicle;
    Car.prototype.constructor = Car;

    Truck.prototype = new Vehicle;
    Truck.prototype.constructor = Truck;

    window.Vehicle = Vehicle;
    window.Car = Car;
    window.Truck = Truck;
})();

var car1   = new Car,
    car2   = new Car,
    truck1 = new Truck;

alert([car1.id, car2.id, truck1.id]);
pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • Deleted my answer as browser hadn't updated there had been other answers, your's was almost identical to mine but hadn't had time to add the dictionary lookup by name. – Paul Hadfield Sep 20 '11 at 14:54
  • -1 [`.name`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Name) is non standard. – Raynos Sep 20 '11 at 15:12
1

Using Object.create and pd

// Vehicle prototype
var Vehicle = {
  drive: function() {
    // code
  },
  name: "Vehicle",
  counter: 0
}

// Car prototype
var Car = Object.create(Vehicle, pd({
  name: "Car",
  counter: 0
  // car methods
}));

// vehicle factory
var vehicle = function(data, proto) {
  proto = proto || Vehicle;
  data.id = proto.name + proto.counter++;
  return Object.create(proto, pd(data));
};

// car factory
var car = function(data) {
  return vehicle(data, Car);
};

What you want here is to store a name and a counter on the prototypes. Then your vehicle factory just generates a new id on the prototype counter & name.

Raynos
  • 166,823
  • 56
  • 351
  • 396
0

I borrowed some ideas from @pimvdb's post and came up with this Coffeescript snippet:

class Vehicle
    @ids = {}
    @name = 'Vehicle'
    constructor: ->
        @constructor.ids[@constructor.name] ?= 0
        @type = @constructor.name
        @id = "#{@type}-#{@constructor.ids[@type]++}"

class Car extends Vehicle
    @name = 'Car'

class Truck extends Vehicle
    @name = 'Truck'

car = new Car
alert car.id
car = new Car
alert car.id
truck = new Truck
alert truck.id
car = new Car
alert car.id

Can be tested here: http://jashkenas.github.com/coffee-script/ (click on "try coffeescript")

Seems exacltly what I was looking for, thanks.

Giacomo
  • 11,087
  • 5
  • 25
  • 25
-1

Translating your example to some more formal description: some constructors have their own ID dealer.

// a Vehicle has an id property, but no id dealer
function Vehicle( id ){
   this.id=id;
}
Vehicle.prototype.id = function(){ return this.id; }

// some objects can deal IDs
function IDDealer(){
   this.nextid=0;
}
IDDealer.prototype.nextId = function(){
   this.nextid ++;
   return this.nextid;
}


function Car(){
   Vehicle(this, idDealer.nextId() );
}
// a Car has a proper ID dealer
Car.prototype.idDealer = new IDDealer();


function Truck(){
   Vehicle(this, idDealer.nextId() );
}
// a Truck has a proper ID dealer
Truck.prototype.idDealer = new IDDealer();
xtofl
  • 40,723
  • 12
  • 105
  • 192