行为模式:命令模式
简介
命令模式是将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。
举个简单的例子:
我有一个饭店,共有五个厨师:A,B,C,D,E;每个厨师都会做不同的菜,但是我没有菜单,于是客人就必须知道我有几个厨师,他们分别会做什么菜,于是就会产生下面这些情况:
- 客人1想吃青椒炒蛋,于是问了好几个厨师才知道C厨师会做,于是它通知C厨师做青椒炒蛋
- 客人2想吃冒菜,于是他也问了好几个厨师,找到E厨师制作
- ...更多
你会发现客人与厨师耦合度非常之高,这显然不利于饭店的发展,然后我们想一下生活中的真实情况:
每个饭店都会有一份菜单,客户只需要看菜单点菜就可以了,完全不用去管哪个厨师做的,也不用本人去通知厨师。
而菜单就可以理解命令模式,客户只需要发送指令:需要吃的菜;饭店就会通知厨师去做。
命令模式就是为了解耦这种关系,这种关系有两个角色:方法的请求者与方法的实现者
我们在代码中,可能为了使用某个对象的功能,会直接引入该对象去直接使用,而往量级的方向发展,我们可能需要引入一堆对象,然后调用,每个对象其实方法实现都可能会不一样,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对应不同的命令。
命令模式通常适用于以下场景。
- 请求调用者需要与请求接收者解耦时,命令模式可以使调用者和接收者不直接交互。
- 系统随机请求命令或经常增加、删除命令时,命令模式可以方便地实现这些功能。
- 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。
- 当系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作时,可以将命令对象存储起来,采用备忘录模式来实现。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据