Last active
June 23, 2016 03:57
-
-
Save xaethos/7b8ff8a55ea0680f8d65b2ffbbdfcccb to your computer and use it in GitHub Desktop.
Injectable PureMVC commands
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
package com.example; | |
import android.os.Bundle; | |
import android.support.annotation.VisibleForTesting; | |
import org.puremvc.java.interfaces.INotification; | |
import org.puremvc.java.patterns.command.SimpleCommand; | |
import org.puremvc.java.patterns.facade.Facade; | |
import javax.inject.Inject; | |
import javax.inject.Singleton; | |
@Singleton | |
public class FooCommand extends SimpleCommand { | |
/* | |
We'll call the commands via methods, so these don't need to be public. | |
*/ | |
@VisibleForTesting static final String CMD_BAR = "FooCommand.Bar"; | |
@VisibleForTesting static final String CMD_BAZ = "FooCommand.Baz"; | |
/* | |
Same as above. | |
*/ | |
@VisibleForTesting | |
static class BarParams { | |
public final String s; | |
public final int n; | |
private BarParams(String s, int n) { | |
this.s = s; | |
this.n = n; | |
} | |
} | |
/* | |
The command knows how to register itself with the facade. | |
No more keeping lists of command strings in two different classes. | |
*/ | |
@Inject | |
public void register(Facade facade) { | |
facade.registerCommand(CMD_BAR, this); | |
facade.registerCommand(CMD_BAZ, this); | |
} | |
/* | |
Now executing a command becomes as simple as getting a reference to the | |
singleton instance and calling `fooCmd.bar("answer", 42)` | |
*/ | |
public void bar(String s, int n) { | |
/* | |
Of course, we still send notifications behind the scenes. | |
*/ | |
sendNotification(CMD_BAR, new BarParams(s, n)); | |
} | |
public void baz(boolean b, float... fs) { | |
/* | |
How the command packages its parameters becomes an internal | |
implementation detail. | |
*/ | |
Bundle params = new Bundle(); | |
params.putBoolean("bool", b); | |
params.putFloatArray("floats", fs); | |
sendNotification(CMD_BAR, params); | |
} | |
@Override | |
public void execute(INotification notification) { | |
switch (notification.getName()) { | |
case CMD_BAR: | |
doBar((BarParams) notification.getBody()); | |
break; | |
case CMD_BAZ: | |
doBaz((Bundle) notification.getBody()); | |
break; | |
} | |
} | |
private void doBar(BarParams params) { /* ... */ } | |
private void doBaz(Bundle params) { /* ... */ } | |
} | |
/* Executing commands becomes much neater */ | |
class Something { | |
/* | |
We can inject this since we're using Dagger. | |
Providing a `FooCommand.getInstance()` or `facade.getFooCommand()` | |
would be very easy, too. | |
*/ | |
@Inject FooCommand fooCmd; | |
/* | |
Testing that a command is executed with correct parameters | |
becomes much easier: `verify(mockFooCmd).baz(true, 1.0, 3.4, 0.0)` | |
*/ | |
public void doTestableStuff(float f) { | |
fooCmd.baz(true, f, 3.4f, 0.0f); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I like this!
Command
is a singletonregister()
after creating each command. No more figuring out "why doesn't the command run???"sendNotification(...)
inside of methods of commands instead of callingsendNotification
gives us better type safety. We won't be able to do something crazy likesendNotification(CommandFoo.NAME, new CommandBar.Params(...))
.The only thing I'll add is a
default
case in theexecute
method, to maybe throw and exception when an unexpected notification is received and havingSimpleCommand
beabstract
and expect thatregister
be implemented for "real"Command
s.