Created
June 23, 2015 11:40
-
-
Save OriginUnknown/3559ee4e4cd7e747fcfc to your computer and use it in GitHub Desktop.
JavaScript OOP Design Patterns - Bridge Pattern
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
<!doctype html> | |
<html lang="en"> | |
<head> | |
<title>Bridge pattern</title> | |
</head> | |
<body> | |
<script type="text/javascript"> | |
/* | |
* REMOTE CONTROL BUTTONS | |
* Concrete R/C Buttons | |
* ON | |
* OFF | |
* VOLUME UP | |
* VOLUME DOWN | |
* | |
* Dynamic R/C Buttons | |
* UP Button | |
* DOWN Button | |
* LEFT Button | |
* RIGHT Button | |
* MIDDLE Button | |
*/ | |
var EntertainmentSystem = (function () { | |
var self = {}; | |
//Shared private methods | |
function previousItemIsCurrent ( index ) { | |
return index === 0; | |
} | |
function endOfListItem ( index, listings ) { | |
return index + 1 === listings.length; | |
} | |
//Abstract classes | |
function AbstractRemoteControl ( ed ) { | |
var _device = ed; | |
var turnDeviceOn = _device.on.bind( _device ), | |
turnDeviceOff = _device.off.bind( _device ), | |
incrementVolume = _device.volumeUpButton.bind( _device ), | |
decrementVolume = _device.volumeDownButton.bind( _device ); | |
return { | |
"on" : turnDeviceOn, | |
"off" : turnDeviceOff, | |
"volumeUpButton" : incrementVolume, | |
"volumeDownButton" : decrementVolume | |
} | |
} | |
//Abstract class for all derived entertainment devices. | |
function AbstractEntertainmentDevice () { | |
//private properties and methods | |
var _msg = "", _maxVolumeLevel = null, _volumeLevel = 0, | |
validMaxVolumeSettings = function ( v ) { | |
return v !== null && v !== undefined && v !== 0 && typeof(v) === 'number'; //returns boolean | |
}; | |
//public methods to be returned | |
var abOn = function () { | |
_msg = this.getDeviceName.call( this ) + " is on"; | |
return _msg; | |
}; | |
var abOff = function () { | |
_msg = this.getDeviceName.call( this ) + " is turned off"; | |
return _msg; | |
}; | |
var abGetMaxVolumeLevel = function () { | |
if ( _maxVolumeLevel !== null ) { | |
return _maxVolumeLevel; | |
} else { | |
throw new Error( "Maximum volume level has not been set. Please set the maximum volume level." ); | |
} | |
}; | |
var abSetMaxVolumeLevel = function ( newMaxVolumeLevel ) { | |
if ( validMaxVolumeSettings( newMaxVolumeLevel ) ) { | |
_maxVolumeLevel = newMaxVolumeLevel; | |
return _maxVolumeLevel; | |
} else { | |
throw new Error( "Invalid maximum volume level. Value must be a number greater than 0 and is not null or undefined." ); | |
} | |
}; | |
var abVolumeUpButton = function () { | |
if ( _volumeLevel > - 1 && _volumeLevel < _maxVolumeLevel ) { | |
_volumeLevel ++; | |
_msg = "Volume Level for " + this.getDeviceName.call( this ) + " has been increased to " + _volumeLevel; | |
return _msg; | |
} else { | |
_msg = "Unable to increase volume level for " + this.getDeviceName.call( this ) + ". Current volume level is " + _volumeLevel; | |
return _msg; | |
} | |
}; | |
var abVolumeDownButton = function () { | |
if ( _volumeLevel > 0 && _volumeLevel <= _maxVolumeLevel ) { | |
_volumeLevel --; | |
_msg = "Volume Level for " + this.getDeviceName.call( this ) + " has been decreased to " + _volumeLevel; | |
return _msg; | |
} else { | |
_msg = "Unable to decrease volume level for " + this.getDeviceName.call( this ) + ". Current volume level is " + _volumeLevel; | |
return _msg; | |
} | |
}; | |
return {//All derived entertainment devices will have the following methods below by default | |
"on" : abOn, | |
"off" : abOff, | |
"setMaxVolumeLevel" : abSetMaxVolumeLevel, | |
"getMaxVolumeLevel" : abGetMaxVolumeLevel, | |
"volumeUpButton" : abVolumeUpButton, | |
"volumeDownButton" : abVolumeDownButton | |
} | |
} | |
//Concrete implementation for one type of entertainment device : Television | |
self.AddNewTelevision = function ( tvName, maxChannelNum ) { | |
var newTelly = AbstractEntertainmentDevice(),//EXTENDS the AbstractEntertainmentDevice class | |
//private variables and methods below | |
deviceType = "Television", | |
deviceName = tvName || deviceType, currentChannel = 1, | |
tvListings = [ "The Simpsons", "Hollyoaks", "Channel 4 News" ], | |
tvListingIndex = 0, msg = "", maxChannelNumber = parseInt( maxChannelNum ) || null, | |
validMaxChannelNumber = function ( v ) { | |
return v !== null && v !== undefined && v > 0 && typeof(v) === "number"; | |
}, | |
nextChannelIsZero = function () { | |
return currentChannel - 1 === 0; | |
}, | |
okToIncreaseChannel = function () { | |
return maxChannelNumber !== null && currentChannel > 0 && currentChannel < maxChannelNumber; | |
}; | |
//public methods for consumption | |
//Exclusive methods for the Television sub class | |
newTelly.setDeviceName = function ( newName ) { | |
if ( typeof(newName) === 'string' ) { | |
deviceName = newName; | |
return deviceName; | |
} else { | |
throw new Error( "Invalid name for Television device. Name should be a string" ); | |
} | |
}; | |
newTelly.getDeviceName = function () { | |
return deviceName; | |
}; | |
newTelly.getMaxChannels = function () { | |
if ( validMaxChannelNumber( maxChannelNumber ) ) { | |
return maxChannelNumber; | |
} else { | |
throw new Error( "Maximum channel number has not been set. Please set the maximum channel number." ); | |
} | |
}; | |
newTelly.setMaxChannels = function ( newMaxChannelNumber ) { | |
if ( validMaxChannelNumber( newMaxChannelNumber ) ) { | |
maxChannelNumber = newMaxChannelNumber; | |
return this; //this is returned for optional "chaining" purposes | |
} else { | |
throw new Error( "Invalid value. Max channel value should be a number greater than 0." ); | |
} | |
}; | |
//Specific implementations of the signature methods for the Television sub class | |
newTelly.upButton = function () { | |
if ( okToIncreaseChannel() ) { | |
currentChannel ++; | |
msg = "Current channel is " + currentChannel; | |
return msg; | |
} else { | |
throw new Error( "Unable to increase the channel" ); | |
} | |
}; | |
newTelly.downButton = function () { | |
if ( ! nextChannelIsZero() ) { | |
currentChannel --; | |
msg = "Current Channel is " + currentChannel; | |
return msg; | |
} else { | |
throw new Error( "Unable to decrease the channel" ); | |
} | |
}; | |
newTelly.leftButton = function () { | |
if ( previousItemIsCurrent( tvListingIndex ) ) { | |
tvListingIndex = 0; | |
return tvListings[ tvListingIndex ];//return current listing (first item in the array) | |
} else { | |
msg = tvListings[ tvListingIndex ]; | |
tvListingIndex --; | |
return msg; | |
} | |
}; | |
newTelly.rightButton = function () { | |
if ( endOfListItem( tvListingIndex, tvListings ) ) { | |
msg = "Unable to get further listings at this time"; | |
return msg; | |
} else { | |
tvListingIndex ++; | |
return tvListings[ tvListingIndex ]; | |
} | |
}; | |
return newTelly; | |
}; | |
//Concrete implementation of the AbstractRemoteControl class for the Television remote control | |
self.CreateTelevisionRemoteControl = function ( tv ) { | |
var telly = tv, tvRemoteControl = AbstractRemoteControl( tv );//EXTENDS the AbstractRemoteControl class | |
//Add the Television specific methods onto the television remote control object | |
tvRemoteControl.upButton = telly.upButton; | |
tvRemoteControl.downButton = telly.downButton; | |
tvRemoteControl.leftButton = telly.leftButton; | |
tvRemoteControl.rightButton = telly.rightButton; | |
return tvRemoteControl; | |
}; | |
self.AddNewDVDPlayer = function ( dvdPlayerName ) { | |
var newDVDPlayer = AbstractEntertainmentDevice(), | |
deviceType = "DVD Player", | |
deviceName = dvdPlayerName || deviceType, | |
volumeLevel = 0, maxVolumeLevel = null, msg = "", | |
chapterIndex = 0, enableSubtitles = false, | |
chapters = [ "Bart the Fink", "Krusty gets Kancelled", "Lisa Vs the Monorail" ];//DVD chapters | |
newDVDPlayer.setDeviceName = function ( newName ) { | |
if ( typeof(newName) === 'string' ) { | |
deviceName = newName; | |
return deviceName; | |
} else { | |
throw new Error( "Invalid name for DVD Player device. Name should be a string" ); | |
} | |
}; | |
newDVDPlayer.getDeviceName = function () { | |
return deviceName; | |
}; | |
//DVD Class extends the AbstractEntertainmentDevice class by adding DVD specific methods to this function | |
newDVDPlayer.upButton = function () { | |
if ( ! enableSubtitles ) { | |
enableSubtitles = true; | |
msg = "Subtitles are enabled"; | |
return msg; | |
} else { | |
msg = "Subtitles have already been enabled"; | |
return msg; | |
} | |
}; | |
newDVDPlayer.downButton = function () { | |
if ( enableSubtitles ) { | |
enableSubtitles = false; | |
msg = "Subtitles have been disabled"; | |
return msg; | |
} else { | |
msg = "Subtitles have already been disabled"; | |
return msg; | |
} | |
}; | |
newDVDPlayer.leftButton = function () { | |
if ( previousItemIsCurrent( chapterIndex ) ) { | |
chapterIndex = 0; | |
return chapters[ chapterIndex ]; | |
} else { | |
msg = chapters[ chapterIndex ]; | |
chapterIndex --; | |
return msg; | |
} | |
}; | |
newDVDPlayer.rightButton = function () { | |
if ( endOfListItem( chapterIndex, chapters ) ) { | |
msg = "End of chapter listings"; | |
return msg; | |
} else { | |
chapterIndex ++; | |
return chapters[ chapterIndex ]; | |
} | |
}; | |
return newDVDPlayer; | |
}; | |
self.CreateDVDPlayerRemoteControl = function ( dvdPlayer ) { | |
var dvdDevice = dvdPlayer, dvdRemoteControl = AbstractRemoteControl( dvdPlayer );//EXTENDS the AbstractRemoteControl class | |
//Add the DVD player specific methods onto the DVD Player remote control object | |
dvdRemoteControl.upButton = dvdDevice.upButton; | |
dvdRemoteControl.downButton = dvdDevice.downButton; | |
dvdRemoteControl.leftButton = dvdDevice.leftButton; | |
dvdRemoteControl.rightButton = dvdDevice.rightButton; | |
return dvdRemoteControl; | |
}; | |
return self; | |
})(); | |
//Set up your telly - add it to your entertainment system | |
var Samsung = EntertainmentSystem.AddNewTelevision( "Chump" ).setMaxChannels( 3 ); | |
Samsung.setMaxVolumeLevel( 3 ); | |
//Use your remote control to control your telly by passing in your tv as an argument | |
//for the remote control to use | |
var SamsungRemoteControl = EntertainmentSystem.CreateTelevisionRemoteControl( Samsung ); | |
console.log( SamsungRemoteControl.on() ); | |
console.log( SamsungRemoteControl.off() ); | |
console.log( SamsungRemoteControl.volumeUpButton() );//volume 1 | |
console.log( SamsungRemoteControl.volumeUpButton() );//volume 2 | |
console.log( SamsungRemoteControl.volumeUpButton() );//volume 3 | |
console.log( SamsungRemoteControl.volumeUpButton() );// returns "Unable to increase volume level for Chump. Current volume level is 3" | |
console.log( SamsungRemoteControl.volumeDownButton() );//volume 3 | |
console.log( SamsungRemoteControl.volumeDownButton() );//volume 2 | |
console.log( SamsungRemoteControl.volumeDownButton() );//volume 1 | |
console.log( SamsungRemoteControl.volumeDownButton() );// returns "Unable to decrease volume level for Chump. Current volume level is 0" | |
//Television specific remote controls - idea for controls was based on Sky Digital's box | |
console.log( SamsungRemoteControl.upButton() );//channel 2 | |
console.log( SamsungRemoteControl.upButton() );//channel 3 | |
//console.log(SamsungRemoteControl.upButton());//returns an Exception | |
console.log( SamsungRemoteControl.downButton() );//channel 2 | |
console.log( SamsungRemoteControl.downButton() );//channel 1 | |
//console.log(SamsungRemoteControl.downButton());//returns Exception | |
console.log( SamsungRemoteControl.leftButton() );//returns scheduled tv show for current time -> "The Simpsons" | |
console.log( SamsungRemoteControl.rightButton() );//returns "Hollyoaks" | |
console.log( SamsungRemoteControl.rightButton() );//returns "Channel 4 News" | |
console.log( SamsungRemoteControl.rightButton() );//return "Unable to get further listings at this time" | |
//Add your brand spanking new DVD player to your entertainment system | |
var SonyDVDPlayer = EntertainmentSystem.AddNewDVDPlayer( "Sony Universal" ); | |
SonyDVDPlayer.setMaxVolumeLevel( 4 ); | |
//Tell your DVD remote control to control the DVD player | |
var DVDPlayerRemoteControl = EntertainmentSystem.CreateDVDPlayerRemoteControl( SonyDVDPlayer ); | |
//Play around with your DVD remote control device | |
console.log( DVDPlayerRemoteControl.on() );//Sony Universal is on | |
console.log( DVDPlayerRemoteControl.off() );//Sony Universal is turned off | |
console.log( DVDPlayerRemoteControl.volumeUpButton() );//DVD volume increased to 1 | |
console.log( DVDPlayerRemoteControl.volumeUpButton() );//DVD volume increased to 2 | |
console.log( DVDPlayerRemoteControl.volumeDownButton() );//DVD volume decreased to 1 | |
//DVD player remote control specific commands | |
console.log( DVDPlayerRemoteControl.upButton() );//returns "Subtitles are enabled" | |
console.log( DVDPlayerRemoteControl.upButton() );//returns "Subtitles have already been enabled" | |
console.log( DVDPlayerRemoteControl.downButton() );//returns "Subtitles have been disabled" | |
console.log( DVDPlayerRemoteControl.downButton() );//return "Subtitles have already been disabled" | |
console.log( DVDPlayerRemoteControl.leftButton() );//returns "Bart the Fink" | |
console.log( DVDPlayerRemoteControl.rightButton() );//returns "Krusty gets Kancelled" | |
console.log( DVDPlayerRemoteControl.rightButton() );//returns "Lisa Vs the Monorail" | |
console.log( DVDPlayerRemoteControl.rightButton() );//returns "End of chapter listings" | |
console.log( DVDPlayerRemoteControl.leftButton() );//returns "Lisa Vs the Monorail" | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment