Going to start by trying an object proxy. If that doesn't work well going to use if else conditions, if in browser do this else if on desktop do this
.
It feels like there could be a better way but I don't see it.
The benefit of object proxy or if else statements is:
- I or another developer can drop in one class when needed instead of multiple classes or sub classes. Instead of having instances of BrowserEditor, DesktopEditor, and MobileEditor I can just drop in Editor. Less management.
- Using one class instead of multiple or sub classes is that the one class takes care of talking to all the different parts. If a developer needs to make changes he just has one class to manage. Using multiple classes you have to make sure to override each method (could be overlooked) or implement the interface in two or more places. Less separate parts and less chance of forgetting to update, add or remove code across multiple classes.
- When it comes time to use the class the developer just has to be concerned with addressing one instance instead of multiple. He can set properties and values to the same instance in his application instead of managing multiple instances. His code doesn't have if else statements all over the place.
This last point is important in languages that target multiple platforms from the same code base. So in my case I can use a single code base and export to mobile, desktop or browser.
Supporting cross platform development was a big feature before Steve Jobs destroyed all the lessons and progress towards unification that the web had taught us. His walled garden model and restriction of technology was soon followed by Google, Microsoft, RIM and others.
Instead of the benefit of publishing your content to the web to make it accessible to all devices he blocked plugins like the JavaFX player, Silverlight player, Flash Player, Unity Player and others. Instead of publishing to the world through the ubiquity of the web, you had to publish through his app store and if you chose to sell your content he got to take a cut (a huge cut).
He preached that plugins were a problem on mobile devices (and then it spread that plugins were a problem on desktop environments) while secretly allowing his own plugins like Quicktime in Safari and installing app launcher in other browsers. If you are on Mac look at the plugins in your browser. There's one from Apple right there. As further proof, the few the things he said about plugins that were true, he didn't allow those plugins the opportunity to fix them. Plugin authors added power management, increased security and other features and fixed the issues he mentioned. It was never about the issues it was about control. If you need a break.
Anyway, the problem wasn't plugins, it was about control. And the very argument that plugins are an unsolvable problem is saying that software is an unsolvable problem. Software, is not an inflexible medium. If there is a bug found in a plugin or a browser or an operating system it can be fixed because it's [expletive deleted] software not hardware! Bugs are fixed every [deleted] day by Apple, MS, Google and so on!
Anyway, the question is about cross platform development which is why I'm bring this all up. This is something that Adobe, Oracle (Java?), and Microsoft supported with tons of resources for many many years until they let the uneducated tech media talk them into all using HTML (with a fancy new imaginary specification that does or will do everything plugins do) and JavaScript. And even now they are the best technologies of 1995. Except that now Microsoft is reasserting itself and standing up for cross platform development and has released Visual Studio for Mac (it was once only a Windows IDE). And hopefully other companies with some [deleted] [deleted] will do the same.
Sorry not sorry, rant over.
After sleeping on @bikemans868's suggestion it reminded me of a design pattern I saw used before (don't remember the name).
It goes like this, I'm a framework author and I want to create a button but this button has to work in two different environments. Each environment has a different syntax to get it to work. I don't want the developer using my button to worry about creating different buttons for each environment.
So I create MyButton class and it has all the methods and API that I want. I then create two additional classes for environment A and environment B. Then at runtime or compile time I determine what environment I'm in and then set the implementation in the Button class.
In the following code I set the implementation in the constructor. So the class looks like this:
public class Button implements IButton {
public function Button() {
// the registration could take place somewhere else
if (desktop) {
ImplementationClass = getClass("com.example.DesktopButton");
}
else if (browser) {
ImplementationClass = getClass("com.example.BrowserButton");
}
implementation = new ImplementationClass();
}
public var ImplementationClass:Object;
public var implementation:IButton;
public function setLabel(value:String):void {
implementation.setLabel(value);
}
}
public class DesktopButton implements IButton {
public function setLabel(value:String):void {
button.label = value;
}
}
public class BrowserButton implements IButton {
public function setLabel(value:String):void {
ExternalInterface.call("function(value) { document...button.label = value; }", value);
}
}
Also, I tried ObjectProxy and that only abstracts out the first method. It fails because the proxy only passes in the name of the method but nothing after it. With ExternalInterface I have to pass the full block of code rather and then return a value.
The object proxy call method:
function callProperty(name:String, ...args):* {
if (isDesktop) {
return myObject[name].apply(this, args);
}
else {
return ExternalInterface.call("function (name, args) { return myObject[name].apply(this, args); }", name, args);
}
}
so this works:
myProxy.doMethod(value1, value2);
But fails with this:
myProxy.getElement(id).getTextRange(start, end);
That's because I can't return a reference from another vm besides other limitations.
Update:
I found a real world example for the DragManager class that I'm going to model it after. In the browser the class uses mx.managers.DragManagerImpl and on the desktop it uses NativeDragManagerImpl that interacts with the operating system: