編輯:關於Android編程
命令模式是行為型模式之一。總體來說並不難理解,只是比較繁瑣,他會將簡單的調用關系解耦成多個部分,增加類的復雜度,但是即便如此,命令模式的結構依然清晰。
將一個請求封裝成一個對象,從而讓用戶使用不同的請求把客戶端參數化;對請求排隊或者記錄請求日志,以及支持可撤銷的操作。
(1)需要抽出待執行的動作,然後以參數的形式提供出來。
(2)在不同的時刻指定、排列和執行請求。一個命令對象可以有與初始請求無關的生存期。
(3)需要支持操作取消。
(4)支持修改日志功能,這樣當系統崩潰時,這些修改可以被重做一遍。
(5)需要支持事務操作。
以推箱子游戲為例,一般游戲中會有五個按鈕,分別是左移、右移、下移、上移和撤銷。那麼玩游戲的人就是客戶端,五個按鈕就是調用者,執行具體按鈕命令的方法是命令角色。
接收者角色:推箱子游戲
public class PushBox {
/**
* 執行向左命令
*/
public void toLeft(){
System.out.println("向左");
}
/**
* 執行向右命令
*/
public void toRight(){
System.out.println("向右");
}
/**
* 執行向下命令
*/
public void toDown(){
System.out.println("向下");
}
/**
* 執行向上命令
*/
public void toUp(){
System.out.println("向上");
}
/**
* 執行撤銷命令
*/
public void revoke(){
System.out.println("撤銷");
}
}
命令者抽象
public interface Command {
/**
* 命令執行方法
*/
void execute();
/**
* 獲取命令類型
*/
void getCommand();
}
具體命令者,左移命令類
public class LeftCommand implements Command{
//持有一個接受推箱子游戲對象的引用
private PushBox pushBox;
public LeftCommand(PushBox pushBox){
this.pushBox = pushBox;
}
@Override
public void execute() {
//調用具體命令
pushBox.toLeft();
}
@Override
public void getCommand() {
System.out.print("向左-->");
}
}
具體命令者,右移命令類
public class RightCommand implements Command{
//持有一個接受推箱子游戲對象的引用
private PushBox pushBox;
public RightCommand(PushBox pushBox){
this.pushBox = pushBox;
}
@Override
public void execute() {
//調用具體命令
pushBox.toRight();
}
@Override
public void getCommand() {
System.out.print("向右-->");
}
}
具體命令者,上移命令類
public class UpCommand implements Command{
//持有一個接受推箱子游戲對象的引用
private PushBox pushBox;
public UpCommand(PushBox pushBox){
this.pushBox = pushBox;
}
@Override
public void execute() {
//調用具體命令
pushBox.toUp();
}
@Override
public void getCommand() {
System.out.print("向上-->");
}
}
具體命令者,下移命令類
public class DownCommand implements Command{
//持有一個接受推箱子游戲對象的引用
private PushBox pushBox;
public DownCommand(PushBox pushBox){
this.pushBox = pushBox;
}
@Override
public void execute() {
//調用具體命令
pushBox.toDown();
}
@Override
public void getCommand() {
System.out.print("向下-->");
}
}
具體命令者,撤銷命令類
public class RevokeCommand implements Command{
//持有一個接受推箱子游戲對象的引用
private PushBox pushBox;
public RevokeCommand(PushBox pushBox){
this.pushBox = pushBox;
}
@Override
public void execute() {
//調用具體命令
pushBox.revoke();;
}
@Override
public void getCommand() {
}
}
請求者類,命令由按鈕發起
public class Buttons {
private LeftCommand leftCommand; //向左移動的命令對象引用
private RightCommand rightCommand; //向右移動的命令對象引用
private UpCommand upCommand; //向上移動的命令對象引用
private DownCommand downCommand; //向下移動的命令對象引用
private RevokeCommand revokeCommand; //撤銷命令對象引用
private ArrayList commandList = new ArrayList();//用於記錄命令動作
/**
* 獲取執行命令
*/
public void getCommandList(){
for(Command c : commandList){
c.getCommand();
}
System.out.println("");
}
/**
* 設置向左移動的命令對象
*
* @param leftCommand 向左移動的命令對象
*/
public void setLeftCommand(LeftCommand leftCommand){
this.leftCommand = leftCommand;
}
/**
* 設置向右移動的命令對象
*
* @param rightCommand 向右移動的命令對象
*/
public void setRightCommand(RightCommand rightCommand){
this.rightCommand = rightCommand;
}
/**
* 設置向上移動的命令對象
*
* @param upCommand 向上移動的命令對象
*/
public void setUpCommand(UpCommand upCommand){
this.upCommand = upCommand;
}
/**
* 設置向下移動的命令對象
*
* @param downCommand 向下移動的命令對象
*/
public void setDownCommand(DownCommand downCommand){
this.downCommand = downCommand;
}
/**
* 設置撤銷命令對象
*
* @param revokeCommand 撤銷命令對象
*/
public void setRevokeCommand(RevokeCommand revokeCommand){
this.revokeCommand = revokeCommand;
}
/**
* 按下向左按鈕
*/
public void toLeft(){
leftCommand.execute();
commandList.add(leftCommand);
}
/**
* 按下向右按鈕
*/
public void toRight(){
rightCommand.execute();
commandList.add(rightCommand);
}
/**
* 按下向上按鈕
*/
public void toUp(){
upCommand.execute();
commandList.add(upCommand);
}
/**
* 按下向下按鈕
*/
public void toDown(){
downCommand.execute();
commandList.add(downCommand);
}
/**
* 按下撤銷按鈕
*/
public void toRevoke(){
revokeCommand.execute();
commandList.remove(commandList.size()-1);
}
}
客戶端調用
public class Client {
public static void main(String[] args) {
//首先創建游戲
PushBox pushBox = new PushBox();
//根據游戲構造5種命令
LeftCommand leftCommand = new LeftCommand(pushBox);
RightCommand rightCommand = new RightCommand(pushBox);
UpCommand upCommand = new UpCommand(pushBox);
DownCommand downCommand = new DownCommand(pushBox);
RevokeCommand revokeCommand = new RevokeCommand(pushBox);
//按鈕可以執行不同命令
Buttons buttons = new Buttons();
buttons.setLeftCommand(leftCommand);
buttons.setRightCommand(rightCommand);
buttons.setUpCommand(upCommand);
buttons.setDownCommand(downCommand);
buttons.setRevokeCommand(revokeCommand);
//執行操作
buttons.toLeft();
buttons.toDown();
buttons.toDown();
buttons.toRight();
buttons.getCommandList();
buttons.toRevoke();
buttons.toUp();
buttons.toLeft();
buttons.toDown();
buttons.toUp();
buttons.getCommandList();
}
}
執行結果
向左
向下
向下
向右
向左-->向下-->向下-->向右-->
撤銷
向上
向左
向下
向上
向左-->向下-->向下-->向上-->向左-->向下-->向上-->
在這麼長的代碼之後是不是覺得很煩瑣,明明可以很簡單的實現,如下:
public class Client {
public static void main(String[] args) {
//首先創建游戲
PushBox pushBox = new PushBox();
pushBox.toDown();
pushBox.toRight();
pushBox.toUp();
}
}
其實設計模式有一個重要的原則:對修改關閉對擴展開放。如果使用如上的簡單方式,那麼以後的修改只能去修改PushBox類,然後修改Client類,這顯然違反了這一原則。如果使用命令模式,那麼Client類無需修改,只需要修改PushBox類的內部操作,Client類無需知道具體的內部實現。
設計模式的使用之前也有提到,主要是要看當前場景的復雜度和以後的需求進行擴展、維護等方面,完全使用設計模式也是不提倡的,這就需要設計者權衡利弊了。
PackageManagerService中,其對包的相關消息處理右其內部類PackageHandler承擔,其將需要處理的請求作為對象通過消息傳遞給相關的方法,而對於包的安裝、移動以及包大小的測量則分別封裝為HandlerParams的具體子類InstallParams、MoveParams和MeasureParams。源碼如下:
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();
}
可以看出HandlerParams也是一個抽象命令者。
命令模式的封裝性很好,更弱的耦合性,更靈活的控制性以及更好的擴展性。
類的膨脹,大量衍生類的創建。
鏈接:命令模式
今年3月,Google 破天荒提前半年發布了 Android N 開發者預覽版。當然,作為一個不合格的谷粉並沒有第一時間體驗安裝,因為至今仍然能夠回憶起來去年今日此門中(
在上圖中,除了最後一個紅色的方框,其它方框都是adb shell下的命令。【1】在Android程序中,一般創建的數據庫存放在 /data/data/[應用程序包名]/d
官方有話這樣說: A RemoteViews object (and, consequently, an App Widget) can support the fo
前言很多程序猿(媛)都對消息處理機制做過分析,大家都基本了解了MessageQueue、Handler、Looper之間相互之間怎麼協同工作,但是具體到消息是如何傳遞,取