Created
February 16, 2013 18:14
-
-
Save jeffschwartz/4967997 to your computer and use it in GitHub Desktop.
Demonstrates how to use object composition instead of inheritance to create rich objects in JavaScript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Demonstrates using object composition | |
* instead of inheritance. | |
* | |
* Using inheritance a car would inherit from vehicle | |
* and we'd have to fashion that relationship using | |
* either pseudo classical inheritance or prototypal | |
* inheritance. By using composition to create | |
* objects you can avoid the hassles of using | |
* either form of inheritance. | |
*/ | |
(function () { | |
"use strict"; | |
/// for utility | |
var show = function ( output ) { | |
if ( typeof output != 'undefined' ) { | |
console.log( output ); | |
} | |
}; | |
/// composes a vehicle object | |
var makeVehicle = function ( spec ) { | |
var vehicle = {}; | |
if ( typeof spec.type === 'undefined' ) { | |
throw "makeVehicle() requires spec.type to be defined" | |
} | |
spec.sound = spec.sound || "this vehicle doesn't have a horn"; | |
spec.model = spec.model || ''; | |
spec.mileage = spec.mileage || 0; | |
var getType = function () { | |
return spec.type; | |
}; | |
var getSound = function () { | |
return spec.sound; | |
}; | |
var getModel = function () { | |
return spec.model; | |
}; | |
var getMileage = function () { | |
return spec.mileage; | |
}; | |
var honk = function ( n ) { | |
if ( typeof n === 'number' ) { | |
var sound = getSound(); | |
while ( n ) { | |
show( (sound + " " + sound) ); | |
n -= 1; | |
} | |
} | |
}; | |
vehicle.getType = getType; | |
vehicle.getSound = getSound; | |
vehicle.getModel = getModel; | |
vehicle.getMileage = getMileage; | |
vehicle.honk = honk; | |
return vehicle; | |
}; | |
/// composes a car object | |
var makeCar = function ( spec ) { | |
var car; | |
if ( typeof spec.model === 'undefined' ) { | |
throw 'makecar() expects spec.model to be defined'; | |
} | |
spec.type = 'car'; | |
spec.sound = 'Beep!'; | |
spec.bodyType = spec.bodyType || 'sedan'; | |
spec.engineType = spec.engineType || 'gasoline'; | |
spec.numberOfWheels = 4; | |
var getBodyType = function () { | |
return spec.bodyType; | |
}; | |
var getNumberOfWheels = function () { | |
return spec.numberOfWheels; | |
}; | |
var getEngineType = function () { | |
return spec.engineType; | |
}; | |
car = makeVehicle( spec ); | |
car.getBodyType = getBodyType; | |
car.getNumberOfWheels = getNumberOfWheels; | |
car.getEngineType = getEngineType; | |
return car; | |
}; | |
/// make a car using composition | |
var car1 = makeCar( {model : 'Civic', engineType : 'hybrid', mileage : 42000 } ); | |
/// Take a look at the car object in your browser's console | |
/// Notice how the car object now has methods contributed | |
/// by both makeVehicle and makeCar, yet we only called | |
/// makeCar. Internally, makeCar calls makeVehicle. | |
/// | |
/// In OO terms 'a car is a vehicle' and our | |
/// car object reflects that by its composites. | |
/// | |
show( car1 ); | |
/// use composites contributed from makeVehicle | |
show( car1.getType() ); | |
show( car1.getSound() ); | |
show( car1.getModel() ); | |
show( car1.getMileage() ); | |
show( car1.honk( 2 ) ); | |
/// use composites contributed from makeCar | |
show( car1.getBodyType() ); | |
show( car1.getNumberOfWheels() ); | |
show( car1.getEngineType() ); | |
/// Exercise - using this 'library' create a motorcycle | |
/// and use its composites to get at its information in | |
/// the same way I did above for a car. | |
}()); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment