前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式之命令模式

设计模式之命令模式

作者头像
Dylan Liu
发布2019-12-19 19:06:27
3040
发布2019-12-19 19:06:27
举报
文章被收录于专栏:dylanliudylanliu

简介

命令模式(Command Pattern)属于设计模式中的行为型模式。命令模式实现了施令者与具体命令的解耦,并且可以实现撤销等命令相关功能。

定义

命令模式(Command Pattern):将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。

命令模式的核心是命令,何为命令?其实命令在日常用于中叫请求,调用一个类的方法,其实就是给类发一个命令让它去执行这个方法,命令模式就是将原本的函数调用封装到类中,由方法级别提升到类级别,从而实现请求者与执行者的解耦,并且可以提供更多的功能,譬如撤销,记录日志等。

角色

命令模式的角色有抽象命令角色,具体命令角色,命令接收者角色及命令调用者角色。

抽象命令:定义命令的通用接口,用于提供给调用者统一的调用API 具体命令:实现具体的命令执行逻辑 命令接收者:真正的逻辑实现地方,(命令提供给调用方一个统一界面,真正逻辑并不在命令里实现,如果没有命令接收者,具体命令就需要充当命令接收者的角色) 调用者:请求的发起方

其实应该还有一个协调者角色,它负责初始化具体的命令,设置到调用者中,不过这个一般在main 函数中实现,不列到此处。

模式说明

既然是将对象请求封装为命令,那么所有的代码其实都可以封装成命令模式,区别只是有没有必要。在具体实践中,用户界面相关使用最多,因为命令模式支持的撤销、日志、记录等功能都特别符合用户需求。

在浏览器或手机APP 中,都会提供返回功能,用户只需要点击返回按钮就可以返回到上一层,对于开发人员来说,这个功能浏览器和手机都已经提供了,只需要调用一个 back 就可以。如果让我们来实现,就可以使用命令模式来将 back 映射到撤销功能。

代码语言:javascript
复制
/**
  * 在浏览器中是URL跳转
  * 在手机中是 Activity 跳转
  */
public interface Command<T> {
    void execute(T param);
    void back();
}

public class UrlCommand implements Command<String> {
    private WindowHanlder windowHandler;
    private Window preWindow;
    private UrlReceiver receiver;
    public UrlCommand(UrlReceiver rec) {
        this.receiver = rec;
        
    }
    public void execute(String url) {
        // 保存当前窗口
        this.preWindow = windowHandler.getWindow();
        rec.parseAndRend(url);
    }
    
    public void back() {
        // 将原窗口再设置回去
        windowHandler.setWindow(preWindow);
    }
}

/**
  * url 具体执行
  */
public class UrlReceiver {
    public void parseAndRend(String url) {
        // 获取url 对应内容
        String content = parse(url);
        // 渲染到窗口中
        rend(content);
    }
    
    private void rend(String content) {
        // 渲染窗口
    }
}

public class User {
    public static void main(String[] args) {
        // 在浏览器里用户点击 url
        String url = "";
        UrlCommand command = new UrlCommand(new UrlReceiver());
        command.execute(url);
        
        // 用户点击返回
        command.back();
    }
}

此处 Command 只能支持单个命令的执行撤销,我们可以写一个 宏命令来封装一串命令执行后的撤销功能

代码语言:javascript
复制
public class MacroUrlCommand implements Command<String> {
    private Stack<Command> commands = new Stack<>();
    private UrlReceiver receiver;
    public MacroUrlCommand(UrlReceiver rec) {
        this.receiver = rec;
        
    } 
    public void execute(String url) {
        UrlCommand command = new UrlCommand(receiver);
        commands.push(command);
        command.execute(url);
    }
    
    public void back() {
        if(CollectionUtils.isEmpty(commands)) {
            return;
        }
        
        Command last = commands.pop();
        last.back();
    }
}

使用场景

  • 请求方与接收方解耦,请求方不需要知道接收方的细节,就像我们使用遥控器调节电视,不需要知道原理,只需要按一下按钮
  • 统一用户界面。开关电灯和开关电脑可以使用相同的用户界面,用户只需要按一下按钮就可以打开电灯或电脑,而不需要重新学习。命令模式通过抽象请求,来实现统一的命令界面
  • 有撤销等功能要求的时候。命令模式定义中就含有此类功能,如果用户要求支持撤销,命令模式是天然的选择
  • 需要支持 redo 和 undo。 数据库等软件在执行插入删除等命令前会将命令记录下来,以便系统崩溃时可以重建。也可以在执行命令后撤销对系统对修改

优点

  • 请求者与实现者解耦,两个可以独立变化
  • 命令可以结合起来变成组合命令(类似装饰模式)
  • 命令作为一个执行单元,支持 redo 和 undo(为避免命令过重,可以与备忘录模式结合)
  • 简单的批处理。可以对系统发一系列命令,系统顺序处理,降低通信成本

缺点

  • 具体命令很容易膨胀,导致系统越来越难以维护
  • 命令对原本直接调用加了一个间接层,增加了系统复杂度,使得理解系统更加困难

模式辨析

Callback 模式:告知某人操作已经完成,操作结果是什么

观察者模式:通知 n(n>=0) 个观察者某个事件发生

命令模式: 封装对对象的调用,使得命令有一个统一界面,相同命令可以相互转换

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 角色
  • 模式说明
  • 使用场景
  • 优点
  • 缺点
  • 模式辨析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档