简介

命令模式是将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。

举个简单的例子:

我有一个饭店,共有五个厨师:A,B,C,D,E;每个厨师都会做不同的菜,但是我没有菜单,于是客人就必须知道我有几个厨师,他们分别会做什么菜,于是就会产生下面这些情况:

  1. 客人1想吃青椒炒蛋,于是问了好几个厨师才知道C厨师会做,于是它通知C厨师做青椒炒蛋
  2. 客人2想吃冒菜,于是他也问了好几个厨师,找到E厨师制作
  3. ...更多

你会发现客人与厨师耦合度非常之高,这显然不利于饭店的发展,然后我们想一下生活中的真实情况:

每个饭店都会有一份菜单,客户只需要看菜单点菜就可以了,完全不用去管哪个厨师做的,也不用本人去通知厨师。

而菜单就可以理解命令模式,客户只需要发送指令:需要吃的菜;饭店就会通知厨师去做。

命令模式就是为了解耦这种关系,这种关系有两个角色:方法的请求者方法的实现者

我们在代码中,可能为了使用某个对象的功能,会直接引入该对象去直接使用,而往量级的方向发展,我们可能需要引入一堆对象,然后调用,每个对象其实方法实现都可能会不一样,A对象有show方法,B对象可能用open方法,这是很正常的事,但是会使得代码耦合度非常的高,如果有一天对象更新迭代了,或者换了一个对象,代码就得发生改动,而我们并不推荐改动原有的代码。

根据以往的经验,采用依赖倒置原则,我们通过声明一个接口依赖,让他们相互遵照这个规则不就好了,但是想法很美好,现实很残酷,并不是所有的代码都能通过简单的一两个接口就能实现的,有可能会有异步的情况,或者其他方式,而对于那些已经存在很久的对象,接口的依赖并不是很好的做法,因为这需要改动旧的代码。

为了实现依赖倒置,命令模式的做法就是包一层,非常简单粗暴,有点类似于代理模式那种,给每个命令(请求)封装成一个个命令对象,命令对象依赖于命令的接口;调用者能也依赖于该接口,这样命令对象随便更换,只要符合接口要求即可,保证了调用者能正确的调用。

而我们的菜单,则是一个命令对象的集合,一般称为宏命令模式

具体的命令的集合怎么写本文就不涉及了,因为不同的业务逻辑管理的方式也不一样。

代码实现

//厨师A:为了省事厨师就会一个菜
class A {
  public beganToCook() {
    console.log("开始做青椒炒蛋");
  }

  public endedToCook() {
    return "青椒炒蛋";
  }
}

//厨师B:为了省事厨师就会一个菜
class B {
  public soup() {
    console.log("开始煲龙骨汤");
  }

  public endedToSoup() {
    return "龙骨汤";
  }
}

//命令对象的接口
interface Command {
  start(): void; //开始做菜
  getDishes(): string; //获取菜品
}

//对青椒炒蛋的命令
class QJCDCommand implements Command {
  private a: A;

  constructor() {
    this.a = new A();
  }

  start() {
    this.a.beganToCook();
  }

  getDishes() {
    return this.a.endedToCook();
  }
}

//对龙骨汤的命令
class LGTCommand implements Command {
  private b: B;

  constructor() {
    this.b = new B();
  }

  start() {
    this.b.soup();
  }

  getDishes() {
    return this.b.endedToSoup();
  }
}

//发送做青椒炒蛋的命令
new QJCDCommand().start();

//发送龙骨汤的命令
new LGTCommand().start();

你会发现最后使用的时候,是一个高度统一的api调用方式,这就带来了一个好处:统一规范

因为大家都是一样的,所以就可以做更多的功能,比如说增加命令模式会要求的:撤销、重做、记录这些功能。

我们只需要声明接口需要这些功能,然后具体的命令对象就各自想办法去实现,我们需要的时候去调用就行了,这样的话代码不会混在一起,各司其职让代码更加健壮。

但是这也会有一些很明显的缺点,比如每个处理都需要包一层,这就会导致命令对象的数量增加,代码的抽离肯定会更加的难,这也是解耦带来的通病。

应用场景

比如软件的菜单,一个个button对应不同的命令。

命令模式通常适用于以下场景。

  1. 请求调用者需要与请求接收者解耦时,命令模式可以使调用者和接收者不直接交互。
  2. 系统随机请求命令或经常增加、删除命令时,命令模式可以方便地实现这些功能。
  3. 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。
  4. 当系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作时,可以将命令对象存储起来,采用备忘录模式来实现。
分类: 设计模式 标签: 菜单设计模式行为模式命令模式解耦

评论

暂无评论数据

暂无评论数据

目录