Analysis of Android source code design patterns and practices (11)
Chapter 2 command mode
Command mode is one of the behavior modes. In general, it is not difficult to understand, but it is complicated. It decouples the simple call relationship into multiple parts to increase the complexity of the class. However, even so, the structure of the command mode is still clear.
1. Definition
Encapsulate a request into an object so that users can parameterize the client using different requests; queue requests or record request logs, and support auditable operations.
2. Use Cases
(1) extract the action to be executed and provide it as a parameter.
(2) specify, sort, and execute requests at different times. A command object can have a lifetime unrelated to the initial request.
(3) The operation must be canceled.
(4) The log modification function is supported, so that the modifications can be redone when the system crashes.
(5) transaction operations must be supported.
3. Simple implementation
In a push box game, for example, there are five buttons in the game: Left shift, right shift, move down, move up, And undo. The player is the client, and the five buttons are the caller. The command role is used to execute the specific button command.
Receiver role: Push box game
Public class PushBox {/*** execute the left command */public void toLeft () {System. out. println ("Left");}/*** execute the right command */public void toRight () {System. out. println ("to the right");}/*** execute the following command */public void toDown () {System. out. println ("down");}/*** execute the up command */public void toUp () {System. out. println ("up");}/*** run the undo command */public void revoke () {System. out. println ("undo ");}}
Imperative Abstraction
Public interface Command {/*** Command Execution Method */void execute ();/*** GET Command type */void getCommand ();}
Specific imperative, left shift command class
Public class LeftCommand implements Command {// hold a reference to the private PushBox pushBox for accepting the push box game object; public LeftCommand (PushBox pushBox) {this. pushBox = pushBox;} @ Override public void execute () {// call the pushBox command. toLeft () ;}@ Override public void getCommand () {System. out. print ("left --> ");}}
Specific imperative, right shift command class
Public class RightCommand implements Command {// hold a reference to the private PushBox pushBox for accepting the push box game object; public RightCommand (PushBox pushBox) {this. pushBox = pushBox;} @ Override public void execute () {// call the pushBox command. toRight () ;}@ Override public void getCommand () {System. out. print ("Right --> ");}}
Specific imperative, move up command class
Public class UpCommand implements Command {// hold a reference to the private PushBox pushBox for a game object that accepts the push box; public UpCommand (PushBox pushBox) {this. pushBox = pushBox;} @ Override public void execute () {// call the pushBox command. toUp () ;}@ Override public void getCommand () {System. out. print ("up --> ");}}
The specific writer moves down the command class.
Public class DownCommand implements Command {// hold a reference to the private PushBox pushBox for a game object that accepts the push box; public DownCommand (PushBox pushBox) {this. pushBox = pushBox;} @ Override public void execute () {// call the pushBox command. toDown () ;}@ Override public void getCommand () {System. out. print ("down --> ");}}
Specific commander, undo command class
Public class RevokeCommand implements Command {// hold a reference to the private PushBox pushBox for accepting the push box game object; public RevokeCommand (PushBox pushBox) {this. pushBox = pushBox;} @ Override public void execute () {// call the pushBox command. revoke () ;;}@ Override public void getCommand (){}}
Requester class. commands are initiated by buttons.
Public class Buttons {private LeftCommand leftCommand; // reference private RightCommand rightCommand to the command object that is moved to the left; // reference private UpCommand upCommand to the command object that moves to the right; // The command object to be moved up references private DownCommand downCommand; // The command object to be moved down references private RevokeCommand revokeCommand; // The command object to be revoked references private ArrayListCommandList = new ArrayList(); // Used to record Command actions/*** get execution Command */public void getCommandList () {for (Command c: commandList) {c. getCommand ();} System. out. println ("");}/*** sets the command object to be moved to the left ** @ param leftCommand refers to the command object to be moved to the left */public void setLeftCommand (LeftCommand leftCommand) {this. leftCommand = leftCommand;}/*** set the command object to move to the right ** @ param rightCommand the command object to move to the right */public void setRightCommand (RightCommand rightCommand) {this. rightCommand = rightCommand;}/*** set the command object to move up ** @ param upCommand the command object to move up */public void setUpCommand (UpCommand upCommand) {this. upCommand = upCommand;}/*** set the command object to move down ** @ param downCommand the command object to move down */public void setDownCommand (DownCommand downCommand) {this. downCommand = downCommand;}/*** set the undo command object ** @ param revokeCommand undo command object */public void setRevokeCommand (RevokeCommand revokeCommand) {this. revokeCommand = revokeCommand;}/*** press the left button */public void toLeft () {leftCommand.exe cute (); commandList. add (leftCommand);}/*** press the right button */public void toRight () {rightCommand.exe cute (); commandList. add (rightCommand);}/*** press the up button */public void toUp () {upCommand.exe cute (); commandList. add (upCommand);}/*** press the down button */public void toDown () {downCommand.exe cute (); commandList. add (downCommand);}/*** press the Undo button */public void torevke () {revokeCommand.exe cute (); commandList. remove (commandList. size ()-1 );}}
Client call
Public class Client {public static void main (String [] args) {// first create the game PushBox pushBox = new PushBox (); // construct Five Commands LeftCommand leftCommand = new LeftCommand (pushBox) based on the game; RightCommand rightCommand = new RightCommand (pushBox); UpCommand upCommand = new UpCommand (pushBox ); downCommand downCommand = new DownCommand (pushBox); RevokeCommand revokeCommand = new RevokeCommand (pushBox); // The button can execute different commands Buttons buttons = new Buttons (); buttons. setLeftCommand (leftCommand); buttons. setRightCommand (rightCommand); buttons. setUpCommand (upCommand); buttons. setDownCommand (downCommand); buttons. setRevokeCommand (revokeCommand); // execute the buttons operation. toLeft (); buttons. toDown (); buttons. toDown (); buttons. toRight (); buttons. getCommandList (); buttons. torevke (); buttons. toUp (); buttons. toLeft (); buttons. toDown (); buttons. toUp (); buttons. getCommandList ();}}
Execution result
To the left down to the right to the left --> down --> to the right --> undo up to the left down to the left --> down --> up --> to the left --> down --> up -->
After such a long code, do you think it is very cumbersome? It can be implemented easily, as shown below:
Public class Client {public static void main (String [] args) {// first create the game PushBox pushBox = new PushBox (); pushBox. toDown (); pushBox. toRight (); pushBox. toUp ();}}
In fact, there is an important principle in the design pattern: the modification is closed and open to the extension. If you use the preceding simple method, you can only modify the PushBox class and then modify the Client class in the future. This obviously violates this principle. If you use the command mode, the Client class does not need to be modified. You only need to modify the internal operations of the PushBox class. The Client class does not need to know the specific internal implementation.
The use of the design model has also been mentioned before. It mainly depends on the complexity of the current scenario and the need for expansion and maintenance in the future. It is not recommended to fully use the design model, this requires the designers to weigh the advantages and disadvantages.
4. Implementation of the command mode in the Android Source Code 1. PackageHandler
In PackageManagerService, The PackageHandler class is responsible for packet-related message processing. The PackageHandler takes the request to be processed as an object and passes it to the relevant method through the message, the package installation, movement, and package size measurement are encapsulatedHandlerParamsSpecific subclassInstallParams,MoveParamsAndMeasureParams. The source code is as follows:
private abstract class HandlerParams { private static final int MAX_RETRIES = 4; /** * Number of times startCopy() has been attempted and had a non-fatal * error. */ private int mRetries = 0; final boolean startCopy() { boolean res; try { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy"); if (++mRetries > MAX_RETRIES) { Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { handleStartCopy(); res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } handleReturnCode(); return res; } final void serviceError() { if (DEBUG_INSTALL) Slog.i(TAG, "serviceError"); handleServiceError(); handleReturnCode(); } abstract void handleStartCopy() throws RemoteException; abstract void handleServiceError(); abstract void handleReturnCode(); }
We can see thatHandlerParamsIt is also an abstract imperative.
5. Summary 1. Advantages
The command mode has good encapsulation, weaker coupling, more flexible control, and better scalability.
2. Disadvantages
Class expansion, creating a large number of category classes.
6. Reference
Link: Command mode