IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 命令模式以及在android中的使用 -> 正文阅读

[移动开发]命令模式以及在android中的使用

一、原理

命令模式将任务请求封装成命令对象,命令对象中封装有任务处理者对象,调用者持有这个命令对象,这就使得调用者和处理者没有直接联系,降低了耦合度。同时,根据不同的请求可以参数化命令对象,可以将多个对象放入到集合中排队执行。命令模式的UML图如下,安利一个UML绘制网站https://app.diagrams.net/。
在这里插入图片描述
命令模式可以适用组合的方式将发出请求的对象和执行请求的对象解耦,这样后面拓展新的命令比较容易;缺点就是会出现过多的具体命令类以及处理者类。

二、实践

那上课为例吧,现在有个一个调用者-教学主任(TeachingDirector)、不同的课程(命令对象TeachChineseCommand、TeachEnglishCommand、TeachMathCommand)以及授课老师(处理者):语文老师(ChineseTeacher)、数学老师(MathTeacher)、英语老师(EnglishTeacher)。规则就是教导主任可以发布上课指令去触发上课命令对象,然后上课命令对象调用具体的老师去执行相应的教学任务。
在这里插入图片描述
ChineseTeacher.java

class ChineseTeacher {
    public void action() {
        LogUtil.d("teach Chinese");
    }
}

EnglishTeacher.java

class EnglishTeacher {
    public void action() {
        LogUtil.d("teach English");
    }
}

MathTeacher.java

class MathTeacher {
    public void action() {
        LogUtil.d("teach Math");
    }
}

Command.java

public interface Command {
    void execute();
}

TeachChineseCommand.java

class TeachChineseCommand implements Command{

    private ChineseTeacher chineseTeacher;

    public TeachChineseCommand(ChineseTeacher chineseTeacher) {
        this.chineseTeacher = chineseTeacher;
    }

    @Override
    public void execute() {
        if (chineseTeacher!=null) {
            chineseTeacher.action();
        }
    }
}

TeachEnglishCommand.java

class TeachEnglishCommand implements Command{

    private EnglishTeacher englishTeacher;

    public TeachEnglishCommand(EnglishTeacher englishTeacher) {
        this.englishTeacher = englishTeacher;
    }

    @Override
    public void execute() {
        if (englishTeacher!=null) {
            englishTeacher.action();
        }
    }
}

TeachMathCommand.java

class TeachMathCommand implements Command{

    private MathTeacher mathTeacher;

    public TeachMathCommand(MathTeacher mathTeacher) {
        this.mathTeacher = mathTeacher;
    }

    @Override
    public void execute() {
        if (mathTeacher!=null) {
            mathTeacher.action();
        }
    }
}

TeachingDirector.java

public class TeachingDirector {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void doAction() {
        if (this.command !=null) {
            this.command.execute();
        }
    }
}

测试代码如下:

private void doTest() {
    TeachChineseCommand teachChineseCommand = new TeachChineseCommand(new ChineseTeacher());
    TeachEnglishCommand teachEnglishCommand = new TeachEnglishCommand(new EnglishTeacher());
    TeachMathCommand teachMathCommand = new TeachMathCommand(new MathTeacher());
    TeachingDirector teachingDirector = new TeachingDirector();
    teachingDirector.setCommand(teachChineseCommand);
    teachingDirector.doAction();

    teachingDirector.setCommand(teachEnglishCommand);
    teachingDirector.doAction();

    teachingDirector.setCommand(teachMathCommand);
    teachingDirector.doAction();
}

log打印如下:

ChineseTeacher.action(L:8): teach Chinese
EnglishTeacher.action(L:8): teach English
MathTeacher.action(L:8): teach Math

此时,教学主任和学科老师没有直接联系,教学主任只需发布具体的上课命令,上课命令会通知指定的学科老师上课,达到解耦的目的。后续如果有其它学科老师以及相应的教学命令对象可以直接添加然后调用教学主任类的setCommand即可,对固有代码修改小,拓展性强。

三、android中命令模式的使用

android中适用的更多的是命令模式的变种-命令对象不再设置接收者,命令对象本身就完成了具体任务。

3.1 PackageManagerService.HandlerParams

在PackageManagerService.java中有一个HandlerParams抽象内部类,HandlerParams的子类InstallParams、MultiPackageInstallParams重写了父类的抽象方法handleStartCopy()和handleReturnCode(),startCopy()会使用模板方法模式调用handleStartCopy()、handleReturnCode()方法。

//PackageManagerService.java
private abstract class HandlerParams {
    /** User handle for the user requesting the information or installation. */
    private final UserHandle mUser;
    String traceMethod;
    int traceCookie;

    HandlerParams(UserHandle user) {
        mUser = user;
    }

    UserHandle getUser() {
        return mUser;
    }

    /**
     * Gets the user handle for the user that the rollback agent should
     * use to look up information about this installation when enabling
     * rollback.
     */
    UserHandle getRollbackUser() {
        // The session for packages installed for "all" users is
        // associated with the "system" user.
        if (mUser == UserHandle.ALL) {
            return UserHandle.SYSTEM;
        }
        return mUser;
    }

    HandlerParams setTraceMethod(String traceMethod) {
        this.traceMethod = traceMethod;
        return this;
    }

    HandlerParams setTraceCookie(int traceCookie) {
        this.traceCookie = traceCookie;
        return this;
    }

    final void startCopy() { //模板方法模式
        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
        handleStartCopy();
        handleReturnCode();
    }

    abstract void handleStartCopy();
    abstract void handleReturnCode();
}

在installStage方法中就会将InstallParams 作为参数传入到mHandler中,mHandler是PackageHandler实例。然后在PackageHandler的doHandleMessage方法中去处理消息,当msg.what是INIT_COPY时取出的msg.obj就是InstallParams 对象,并调用InstallParams的startCopy()方法。

//PackageManagerService.java
void installStage(ActiveInstallSession activeInstallSession) {
    if (DEBUG_INSTANT) {
        if ((activeInstallSession.getSessionParams().installFlags
                & PackageManager.INSTALL_INSTANT_APP) != 0) {
            Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
        }
    }
    final Message msg = mHandler.obtainMessage(INIT_COPY);//msg.what
    final InstallParams params = new InstallParams(activeInstallSession);
    params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
    msg.obj = params;

    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
            System.identityHashCode(msg.obj));
    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
            System.identityHashCode(msg.obj));

    mHandler.sendMessage(msg);
}
……
class PackageHandler extends Handler {

    PackageHandler(Looper looper) {
        super(looper);
    }

    public void handleMessage(Message msg) {
        try {
            doHandleMessage(msg);
        } finally {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        }
    }

    void doHandleMessage(Message msg) {
        switch (msg.what) {
            case INIT_COPY: {
                HandlerParams params = (HandlerParams) msg.obj;
                if (params != null) {
                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                            System.identityHashCode(params));
                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                    params.startCopy();
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
                break;
            }
			……
		}
	}
}

这里的PackageManagerService.java中InstallParams就相当于一个命令对象,其自身实现了具体任务startCopy。

3.2 executor.execute

java中有线程池,线程池对象可以执行execute方法,execute方法参数就是一个Runnable指令,此时就可以创建一个Runnable命令对象,然后通过线程池 去触发对应的操作。

Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
    @Override
    public void run() {
        LogUtil.d("do yourself in Runnable");
    }
});
Thread thread = new Thread(){
    @Override
    public void run() {
        super.run();
        LogUtil.d("do yourself in Thread");
    }
};
executor.execute(thread);
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-25 12:19:37  更:2021-08-25 12:19:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年6日历 -2024/6/2 9:57:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码