第16章 行为型模式—命令模式

1. 命令模式(Command Pattern)的定义

(1)定义

  将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队记录请求日志,以及支持可撤销的操作。

  ①封装请求:抽象出需要执行的动作,封装成对象(有统一的接口)。

  ②参数化:可以用不同的命令对象,去参数化配置客户的请求。(即,将命令对象作为参数去供Invoker调用)。

(2)命令模式的结构和说明

  ①Command:定义命令的接口,声明执行的方法

  ②ConcreteCommand:命令接口实现对象,是“虚”的实现,通常会持有接收者调用接收者的功能来完成命令要执行的操作

  ③Receiver:接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。

  ④Invoker:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

  ⑤Client:创建具体的命令对象,并且设置命令对象的接收者。注意,这个不是我们常规意义上的客户端,而是在组装命令对象和接收者。或许,把这个Client称为装配者会更好,因为真正使用命令的客户端是从Invoker来触发执行。

【编程实验】打飞机游戏

//行为型模式:命令模式
//场景:打飞机游戏
//角色控制器(如玩家)的主要操作:用导弹攻击、炸弹攻击来打飞机以及4个方向移动

#include <iostream>
#include <string>
#include <vector>

using namespace std;
//***********************************************抽象命令接口***********************************
//Command
class FighterCommand
{
public:
    virtual void execute() = 0;
};

//*************************************************接收者**************************************
//Receiver
class Fighter
{
public:
    void missile()
    {
        cout << "用导弹攻击!" << endl;
    }

    void bomb()
    {
        cout << "用炸弹攻击!" << endl;
    }

    void move (int direction)
    {
        switch(direction)
        {
        case 1:
            cout << "向上移动!" << endl;
            break;
        case 2:
            cout << "向下移动!" <<endl;
            break;
        case 3:
            cout << "向左移动!" << endl;
            break;
        case 4:
            cout << "向右移动!" <<endl;
            break;
        default:
            cout << "不移动!" << endl;
        }
    }
};

//*************************************ConcreteCommand***************************************
//导弹攻击命令
class MissileCommand : public FighterCommand
{
private:
    Fighter* fighter;
public:
    MissileCommand(Fighter* fighter)
    {
        this->fighter = fighter;
    }

    void execute()
    {
        fighter->missile();
    }
};

//炸弹攻击命令
class BombCommand : public FighterCommand
{
private:
    Fighter* fighter;
public:
    BombCommand(Fighter* fighter)
    {
        this->fighter = fighter;
    }

    void execute()
    {
        fighter->bomb();
    }
};

//移动命令
class MoveCommand : public FighterCommand
{
private:
    Fighter* fighter;
    int direction;
public:
    MoveCommand(Fighter* fighter, int direction)
    {
        this->fighter = fighter;
        this->direction = direction;
    }

    void execute()
    {
        fighter->move(direction);
    }
};

//***********************************************Invoker***********************************
//请求者
class Controller
{
private:
    FighterCommand* cmdMissible;
    FighterCommand* cmdBomb;
    FighterCommand* cmdMoveLeft;
    FighterCommand* cmdMoveRight;
public:
    Controller(FighterCommand* missible, FighterCommand* bomb,
               FighterCommand* left,     FighterCommand* right)
    {
        cmdMissible  = missible;
        cmdBomb      = bomb;
        cmdMoveLeft  = left;
        cmdMoveRight = right;
    }

    void missible()
    {
        cmdMissible->execute();
    }

    void bomb()
    {
        cmdBomb->execute();
    }

    void moveLeft()
    {
        cmdMoveLeft->execute();
    }

    void moveRight()
    {
        cmdMoveRight->execute();
    }
};

int main()
{
    Fighter fighter; //战士(命令接收者)

    //命令对象
    FighterCommand* cmdMissible  = new MissileCommand(&fighter);
    FighterCommand* cmdBomb      = new BombCommand(&fighter);
    FighterCommand* cmdMoveLeft  = new MoveCommand(&fighter, 3);
    FighterCommand* cmdMoveRight = new MoveCommand(&fighter, 4);

    //玩家(命令发出者)
    //参数化:将命令对象作为参数传入Invoker
    Controller player(cmdMissible, cmdBomb, cmdMoveLeft, cmdMoveRight);

    player.bomb();
    player.missible();
    player.moveLeft();
    player.moveRight();

    //为什么不直接fighter.bomb()之类的呢?
    //有时当发出命令后,我们只关心任务是否完成?但任务具体由哪个Fighter执行
    //并不是我们关心的.如果直接调用,意味着命令的发出者直接叫某个具体的Fighter去做
    //这样两者的耦合太紧.利用命令模式可以将两者解耦。

    return 0;
}

(3)思考命令模式

  ①命令模式的本质封装请求。这是也命令模式的关键。把请求封装成对象,也就是命令对象,并定义了统一的执行操作的接口。这个命令对象可以被存储、转发、记录、处理、撤销等。整个命令模式都是围绕这个对象进行的。

  ②命令模式的动机:在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合——比如需要对行为进行“记录、撤销/重做”、事务”等处理,这种无法抵御变化的紧耦合是不合适的,命令模式的动机就是将一组行为抽象为对象,可以实现二者之间的构耦合。

  ③命令模式的组装和调用

  命令的组装者:用它维护命令的“虚”实现和真实实现之间的关系。(即下图中的Client,但将之定义成组装者更合适。真正的Client是通过Invoker来触发命令的)

  ④命令的接收者:可以是任意的类,对它没有特殊要求。一个接收者可以处理多个命令,接收者提供的方法个数、名称、功能和命令对象中的可以不一样,只要能够通过调用接收者的方法来实现命令对应的功能就可以了。

  ⑤智能命令:在标准的命令模式中,命令的实现类是没有真正实现命令要求的功能的,真正执行命令的功能的是接收者。如果命令对象自己实现了命令要求的功能,而不再需要调用接收者,那这种情况称为智能命令。也有半智能的命令,即命令对象实现一部分,其他的还是需要调用接收者来完成,也就是说命令的功能由命令对象和接收者共同来完成。

【编程实验】菜单项命令

2. 深度理解命令模式

(1)参数化配置:用不同的命令对象,去参数化配置客户的请求。

(2)可撤销的操作:

  ①补偿式(反操作式):如被撤销的操作是加的功能,那么反操作就是减的功能。

  ②存储恢复式:把操作前的状态记录下来,然后要撤销操作时就直接恢复回去就可以了。(该种方式会放到备忘录模式中进行讲解)

(3)宏命令

(4)队列请求

(5)日志请求

3. 命令模式的优缺点

(1)优点

(2)缺点

4. 应用场景

5. 相关模式

时间: 2024-12-24 01:35:11

第16章 行为型模式—命令模式的相关文章

java设计模式--行为型模式--命令模式

1 命令模式 2 概述 3 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤消的操作. 4 5 6 适用性 7 1.抽象出待执行的动作以参数化某对象. 8 9 2.在不同的时刻指定.排列和执行请求. 10 11 3.支持取消操作. 12 13 4.支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍. 14 15 5.用构建在原语操作上的高层操作构造一个系统. 16 17 18 参与者 19 1.Command 20 声明执行操作的接口.

行为型模型 命令模式

行为型模型 命令模式 Command         Command命令的抽象类. ConcreteCommand         Command的具体实现类. Receiver         需要被调用的目标对象. Invorker         通过Invorker执行Command对象. 适用于:         是将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化:对请求排队或记录请求日志,以及支持可撤销的操作. /** * 行为型模型 命令模式 * Command模

Java设计模式(九)责任链模式 命令模式

(十七)责任链模式 责任链模式的目的是通过给予多个对象处理请求的机会,已解除请求发送者与接受者之间的耦合关系.面对对象的开发力求对象之前保持松散耦合,确保对象各自的责任最小化,这样的设计可以使得系统更加容易修改,同时降低产生缺陷的风险. public class ChainTest { public static void main(String[] args) { String pass1="123456"; String pass2="123456"; Stri

15 行为型模式-----命令模式

模式动机(Command Pattern):将请求封装为对象,从而可以用不同的请求对客户进行参数化:对请求进行排队或记录请求日志:设计可撤销的结构等,这些都是命令模式发挥作用的环境.核心思想是:定义一个抽象的Command接口以执行命令.具体如何执行需要其子类ConcreteCommand来实现.ConcreteCommand在执行命令时必须借助于合适的接受该命令的对象,因此其维护一个Receiver指针.这样就能将命令调用者Invoker和命令的实际接收者Receiver进行解耦,调用者针对抽

设计模式--行为型模式--命令模式

=========================命令模式:========================= 废话不说了,先看例子: 模拟对电视机的操作有开机.关机.换台命令.代码如下 Command角色--定义命令的接口,声明执行的方法. 1 //执行命令的接口 2 public interface Command { 3 void execute(); 4 } Receive角色--命令接收者,真正执行命令的对象.实现命令要求实现的相应功能. 1 //命令接收者Receiver 2 pub

设计模式(行为型)之命令模式(Command Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(行为型)之策略模式(Strategy Pattern)>http://blog.csdn.net/yanbober/article/details/45498567 概述 在软件开发中,我们经常需要向某些对象发送请求(调用其中的某个或某些方法),但是并不知道请求的接收

WP8.1学习系列(第十六章)——交互UX之命令模式

命令模式 在本文中 命令类型 命令放置 相关主题 你可以在应用商店应用的几个曲面中放置命令和控件,包括应用画布.弹出窗口.对话框和应用栏.在正确的时间选择合适的曲面可能就是易于使用的应用和很难使用的应用之间的差别. 在应用商店应用中,命令是用户可用来执行操作的交互式 UI 元素.命令与导航元素不同,导航元素用于将用户转移到不同的页面,而命令则可让用户对当前页面执行操作.导航元素使应用可以使用.命令使应用有使用价值. 有关应用中不同命令图面的详细信息,请参阅布置你的 UI. 命令类型 筛选 筛选命

4周第3次课 vim 进入编辑模式 命令模式

进入编辑模式 即进入可以对文档进行编辑的模式 按键 作用 i 在当前字符插入 I 在光标所在行的行首插入 a 在当前字符后插入 A 在光标所在行的行尾插入 o 在光标所在行的下方插入一行 O 在光标所在行的上方插入一行 vim命令模式 命令 作用 /word 向光标之后查找一个字符串word,按 n 向后继续搜索,N向前返回搜索 ?word 向光标之前查找一个字符串word,按 n 向前继续搜索 :n1,n2s/word1/word2/g 在n1-n2行范围之间查找word1并替换为word2,

IOS设计模式之四(备忘录模式,命令模式)

本文原文请见:http://www.raywenderlich.com/46988/ios-design-patterns. 由 @krq_tiger(http://weibo.com/xmuzyq)翻译,如果你发现有什么错误,请与我联系谢谢. 备忘录(Memento)模式 备忘录模式快照对象的内部状态并将其保存到外部.换句话说,它将状态保存到某处,过会你可以不破坏封装的情况下恢复对象的状态,也就是说原来对象中的私有数据仍然是私有的. 如何使用备忘录模式 在ViewController.m中增加