即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

命令模式

编程语言 Gaugamela 8℃ 0评论

在这篇博客里,我们一起来看一下命令模式。


为了理解命令模式,我们可以从生活中常见的场景入手,


例如客户到餐厅点餐的场景。




如上图所示,客户进入餐厅后的最终目的是获取食物。


于是,客户会创建一个订单,并交给服务员。

服务员取得订单后,实际上不需要关心订单上写了什么,


也不需要知道将由谁来准备餐点,


只需要将订单放置到订单窗口,然后喊一声“订单来了”即可。

厨师收到订单通知后,就会准备对应的食物,


并最终递交给客户。


上述场景的交互方式,实际上就是命令模式的雏形。


命令模式可将“动作的调用者”和“动作的执行者”解耦。

例如上图中,服务员就是“动作的调用者”;而厨师就是“动作的执行者”。

服务员不需要和厨师直接打交道,而是递交对应的订单对象;


厨师收到订单对象后,就会执行具体的操作。

通过这种方式,服务员不需要知道厨师准备食物的相关细节,


仅需要明白订单对象的外部接口,例如:放到订单窗口这个动作。


在理解上述生活场景后,我们就可以来看看命令模式的结构了:

如上图所示,Client负责创建一个ConcreteCommand,并设定其接收者。


在之前的例子中,这部分内容相当于:客户创建了一个订单,且订单的执行者指定是厨师(隐含条件)。

Invoker是命令的调用者,负责持有命令对象,


并在某个时刻调用命令对象的execute方法,实施用户的请求。


这个过程就像之前例子中服务员的工作。


服务员负责持有用户的订单,然后在合适的时候,


将订单放到订单窗口,触发厨师进行实际的工作。

Command为所有的命令声明了一个接口。


调用命令的execute方法,就可以让接收者进行相关的动作。


这个也比较好理解。


有的用户可能需要烤肉,有的用户可能需要蛋糕,


但对于服务员而言,这都只不过是订单的细节而已,


服务员只需要关注订单本身,即Command接口。

ConcreteCommand定义了动作和接收者之间的绑定关系。


调用者只要调用execute就可以发出请求,然后由ConcreteCommand调用接收者的一个或多个动作。


ConcreteCommand就对应之前例子中具体的订单了,


客户点了不同的菜时,其实就隐式指定了对应菜系的厨师。


当在订单窗口看到对应的订单后,就会通知具体的厨师工作。

Receiver就是动作的实际执行者了,负责完成用户的请求。


这个就是前例中的厨师了。

从上图可以看出,引入Command对象后,


解除了Invoker和Receiver之间的耦合。


了解命令模式的结构后,我们再来看看命令模式在Head First中的定义。


命令模式将“请求”封装成对象,以便使用不同的请求、队列


或者日志来参数化其他对象。命令模式也支持可撤销的操作。

咋一看这个定义,绝对是一脸懵逼的,个人觉得它的重点其实就是:


将“请求”封装成对象。

一个命令对象就是通过在特定的接收者上绑定一组动作来实现的。


这个对象只需要暴露出一个execute方法,当此方法被调用时,


接收者就会执行绑定的动作。

当然在实际使用时,可以不为命令对象指定具体的接收者,


而是直接在execute中实现许多逻辑。

不过相比较而言,命令对象包含接收者时,


可以将接收者作为参数传递给命令对象,


达到运行时调整的效果,这样的设计可能更有弹性。


命令模式在实际代码得到了广泛的使用。

比较常见的业务结构类似于:


许多实现Command接口的命令对象被加入到Command Queue中;

dispatcher不需要知道每个Command对象具体在干什么,


只需要取出Command对象,然后调用对应的execute方法。


一般情况下,为了提高处理的效率,还会引入多个线程并发处理。

这种设计结构,在之前分析Volley框架时也有提及。


Volley实际上就是将实现Request接口的对象,加入到RequestQueue中。


NetworkDispatcher从RequestQueue中取出Request,


然后调用Request中对应的接口进行实际的处理。

转载请注明:CodingBlog » 命令模式

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情