Last active
August 29, 2015 14:06
-
-
Save 0x1mason/0b9ef9935e3bf5446955 to your computer and use it in GitHub Desktop.
Pseudo code example of lib/devices refactoring using a polymorphic approach. I also tried to use class names that might work with changes bootstrap suggested.
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
The files will make the most sense if you read them in this order: | |
device.js | |
android-base-device.js | |
android-uiautomator.js | |
others.js | |
I hate how gist doesn't give you the ability to keep the files in the original order. |
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
//// android-base-device.js | |
// abstract class that contains common Android code — i.e., functions in android-common.js. | |
internal_to_libs/devices abstract class AndroidBase: extends Device { | |
// android-common.js stuff | |
} |
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
//// android-uiautomator.js | |
// contains device-specific code. this is a concrete implementation. includes all the code in android.js | |
internal_to_libs/devices class AndroidUiAutomator: extends AndroidBase { | |
AndroidUiAutomator.prototype.constructor = function () { | |
console.log("I'm a concrete class. Thanks for creating me.") | |
} | |
// override base class functions when needed | |
AndroidUiAutomator.prototype.pressKeyCode = function (keycode, metastate, cb) { | |
this.proxy(["pressKeyCode", {keycode: keycode, metastate: metastate}], cb); | |
}; | |
AndroidUiAutomator.prototype.longPressKeyCode = function (keycode, metastate, cb) { | |
this.proxy(["longPressKeyCode", {keycode: keycode, metastate: metastate}], cb); | |
}; | |
AndroidUiAutomator.prototype.keyevent = function (keycode, metastate, cb) { | |
helpers.logDeprecationWarning('function', 'keyevent', 'pressKeyCode'); | |
this.pressKeyCode(keycode, metastate, cb); | |
}; | |
// … and so on | |
} |
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
//// device.js | |
// factory method | |
public static Device getDevice(string deviceName, delegate cb) { | |
Device device = null; | |
if (deviceName === “Android 99.99.99”) { // example only—in RL this will be a real device identifier | |
device = new AndroidUiAutomator(); | |
} else if (deviceName === “Android 1.1.1”) { | |
device = new AndroidSelendroid(); | |
} else if (deviceName === “iOS7.1”) { | |
device = new iOS(); | |
} else { | |
cb(new Error(“Unknown device!”)); | |
} | |
return device; | |
} | |
// abstract class that exposes public interface used by all devices. It defines the least Device knowledge accessible | |
// to objects outside lib/devices. Eg, in controller.js, req.device.method will always be defined in the Device class. This | |
// allows for de facto polymorphism in controller.js. | |
public abstract class Device { | |
Device.prototype.constructor = function () { | |
throw "This is an abstract class, you cannot create me directly." | |
} | |
Device.prototype.configure = function (args, caps) { | |
// same code as now | |
}; | |
Device.prototype.setArgFromCap = function (arg, cap) { | |
// same code as now | |
}; | |
// … and so on for all the functions currently in device.js | |
// Device should also include the functions in common.js (assuming they’re all common) and any other function common to all devices | |
Device.prototype.parseElementResponse = function (element) { | |
// same code as now | |
}; | |
Device.prototype.getAtomsElement = function (wdId) { | |
// same code as now | |
}; | |
// … and so on for common.js | |
// now for the abstract functions. they are overridden in derived prototype when appropriate. | |
// Overrides can call the base prototype function if needed: | |
// | |
// DerivedDevice.prototype.foo = function (bar) { | |
// var wu = Device.prototype.foo.call(this, bar); | |
// return specialLogicToChangeWu(wu); | |
// } | |
// | |
Device.prototype.pressKeyCode = function (keycode, metastate, cb) { | |
cb(new NotImplementedError(), null); | |
}; | |
Device.prototype.longPressKeyCode = function (keycode, metastate, cb) { | |
cb(new NotImplementedError(), null); | |
}; | |
Device.prototype.keyevent = function (keycode, metastate, cb) { | |
cb(new NotImplementedError(), null); | |
}; | |
// … and so on for any function invoked outside lib/devices, e.g. in controller.js | |
} |
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
//// android-selendroid.js : same pattern as android-uiautomator.js | |
//// iOS.js, FireFoxOS.js, WindersFon.js, PhewturPhone.js, ad infinitum: No need to worry about “Not implemented” handling. | |
//// Just override the functions you need to implement for the platform and ignore the others; same pattern as | |
//// android-uiautomator.js | |
//// controller.js | |
// somewhere we do something like this and carry on as before. | |
var device = require('device'); | |
req.device = device.getDevice(req.data.deviceName); // again, just an example. the real prop is prolly different. | |
// We proceed polymorphically--we treat req.device as if it were prototype Device, even though the object will | |
// always be a derived prototype. References to a derived prototype's methods are strictly forbidden. | |
// We should never need to know the actual Device subprototype in this context. | |
req.device.longPressKeyCode(); // Regardless of the actual Device subprototype, I can be confident this method | |
// exists for all devices. If I'm worried, there's only one place to check: | |
// device.js. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment