安居多伦多
  • 多市生活
    • 多市生活
    • 加国税务
    • 旅游度假
    • 生活安全
    • 行车安全
    • 窍门集锦
  • 多市书苑
    • 热门
    • 小说
    • 教育
  • 家居信息
    • 家居信息
    • 房屋保养
    • 房屋贷款
    • 房屋租赁
    • 房屋建筑
    • 房前屋后
    • 家居风水
  • 健康保健
    • 健康保健
    • 饮食起居
    • 食品安全
    • 健身锻炼
  • 书苑账户
    • 书苑登入
    • 书苑注册
    • 忘记书苑密码
    • 书苑账户信息
    • 关于我们
    • 联系我们
    • 隐私政策
多伦多书苑
在线书籍:随时阅读,随身听书。
所有书籍 | 人文 | 人物 | 人生 | 健康 | 儿童 | 医学 | 历史 | 历史 | 古典 | 哲学宗教 | 商业 | 外国 | 寓言 | 小说 | 教育 | 风水 | 管理 | 语言 |
为使本公益资源网站能继续提供免费阅读,请勿屏蔽广告。谢谢!报告弹出广告被滥用。
  1. 安居多伦多
  2. 网上书苑
  3. IT
  4. 编程
  5. 深入浅出设计模式

深入浅出设计模式

2021-08-06 0人点赞 0条评论
点赞
x
语速1.0: 2.0
进度0:

上一页   |   返回目录   |   下一页

命令模式

一、引言

忙里偷闲,终于动笔了。是从界面设计中提取出来的一种分离耦合,提高重用的方法。被认为是最优雅而且简单的模式,它的应用范围非常广泛。让我们一起来认识下它吧。

先从起源说起。在设计界面时,大家可以注意到这样的一种情况,同样的菜单控件,在不同的应用环境中的功能是完全不同的;而菜单选项的某个功能可能和鼠标右键的某个功能完全一致。按照最差、最原始的设计,这些不同功能的菜单、或者右键弹出菜单是要分开来实现的,你可以想象一下,word 文档上面的一排菜单要实现出多少个“形似神非”的菜单类来?这完全是行不通的。这时,就要运用分离变化与不变的因素,将菜单触发的功能分离出来,而制作菜单的时候只是提供一个统一的触发接口。这样修改设计后,功能点可以被不同的菜单或者右键重用;而且菜单控件也可以去除变化因素,很大的提高了重用;而且分离了显示逻辑和业务逻辑的耦合。这便是的雏形。

下面我们将仔细的讨论下。

二、定义与结构

《设计模式》中的定义为:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

看起来,好像神通广大。其实的以上功能还要看你是怎么写的——程序总是程序员写出来的,你写啥它才能干啥:)在我看来,其实像很多设计模式一样——通过在你的请求和处理之间加上了一个中间人的角色,来达到分离耦合的目的。通过对中间人角色的特殊设计来形成不同的模式。

当然就是一种特殊设计的结果。

看下是有哪些角色来组成的吧。

1) 命令角色(Command):声明执行操作的接口。有 java 接口或者抽象类来实现。

2) 具体命令角色(Concrete Command):将一个接收者对象绑定于一个动作;调用接收者相应的操作,以实现命令角色声明的执行操作的接口。

3) 客户角色(Client):创建一个具体命令对象(并可以设定它的接收者)。

4) 请求者角色(Invoker):调用命令对象执行这个请求。

5) 接收者角色(Receiver):知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。

以下是的类图,从中可以大致的了解到各个角色之间是怎么来协调工作的。

命令模式

三、举例

本来想接着我的 JUnit 分析来讲解。但是由于在 JUnit 中,参杂了其它的模式在里面,使得的特点不太明显。所以这里将以在 Web 开发中最常见的应用——Struts 中 Action 的使用作为例子。

在 Struts 中 Action 控制类是整个框架的核心,它连接着页面请求和后台业务逻辑处理。

按照框架设计,每一个继承自 Action 的子类,都实现 execute 方法——调用后台真正处理业务的对象来完成任务。

注:继承自 DispatchAction 的子类,则可以一个类里面处理多个类似的操作。这个在这不做讨论。

下面我们将 Struts 中的各个类与中的角色对号入座。

先来看下命令角色——Action 控制类

public class Action {
……
/*
*可以看出,Action 中提供了两个版本的执行接口,而且实现了默认的空实现。
*/
public ActionForward execute( ActionMapping mapping,
ActionForm form,
ServletRequest request,
ServletResponse response)
throws Exception {
try {
return execute(mapping, form, (HttpServletRequest) request,
(HttpServletResponse) response);
} catch (ClassCastException e) {
return null;
}
}
public ActionForward execute( ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return null;
}
}

下面的就是请求者角色,它仅仅负责调用命令角色执行操作。

public class RequestProcessor {
……
protected ActionForward processActionPerform(HttpServletRequest request,
HttpServletResponse response,
Action action,
ActionForm form,
ActionMapping mapping)
throws IOException, ServletException {
try {
return (action.execute(mapping, form, request, response));
} catch (Exception e) {
return (processException(request, response,e, form, mapping));
}
}
}

Struts 框架为我们提供了以上两个角色,要使用 struts 框架完成自己的业务逻辑,剩下的三个角色就要由我们自己来实现了。步骤如下:

1) 很明显我们要先实现一个 Action 的子类,并重写 execute 方法。在此方法中调用业务模块的相应对象来完成任务。

2) 实现处理业务的业务类,来充当接收者角色。

3) 配置 struts-config.xml 配置文件,将自己的 Action 和 Form 以及相应页面结合起来。

4) 编写 jsp,在页面中显式的制定对应的处理 Action。

一个完整的就介绍完了。当你在页面上提交请求后,Struts 框架会根据配置文件中的定义,将你的 Action 对象作为参数传递给 RequestProcessor 类中的processActionPerform()方法,由此方法调用 Action 对象中的执行方法,进而调用业务层中的接收角色。这样就完成了请求的处理。

四、Undo、事务及延伸

在定义中提到,支持可撤销的操作。而在上面的举例中并没有体现出来。其实之所以能够支持这种操作,完全得益于在请求者与接收者之间添加了中间角色。为了实现 undo 功能,首先需要一个历史列表来保存已经执行过的具体命令角色对象;修改具体命令角色中的执行方法,使它记录更多的执行细节,并将自己放入历史列表中;并在具体命令角色中添加 undo 方法,此方法根据记录的执行细节来复原状态(很明显,首先程序员要清楚怎么来实现,因为它和 execute 的效果是一样的)。

同样,redo 功能也能够照此实现。

还有一个常见的用法就是执行事务操作。这就是为什么还叫做事务模式的原因吧。它可以在请求被传递到接收者角色之前,检验请求的正确性,甚至可以检查和数据库中数据的一致性,而且可以结合组合模式的结构,来一次执行多个命令。

使用不仅仅可以解除请求者和接收者之间的耦合,而且可以用来做批处理操作,这完全可以发挥你自己的想象——请求者发出的请求到达命令角色这里以后,先保存在一个列表中而不执行;等到一定的业务需要时,再将列表中全部的操作逐一执行。

哦,实在太灵活了。真是一个很有用的东西啊!

五、优点及适用情况

由上面的讲解可以看出有以下优点:

1) 将调用操作的请求对象与知道如何实现该操作的接收对象解耦。

2) 具体命令角色可以被不同的请求者角色重用。

3) 你可将多个命令装配成一个复合命令。

4) 增加新的具体命令角色很容易,因为这无需改变已有的类。

GOF 总结了的以下适用环境。

1) 需要抽象出待执行的动作,然后以参数的形式提供出来——类似于过程设计中的回调机制。而正是回调机制的一个面向对象的替代品。

2) 在不同的时刻指定、排列和执行请求。一个命令对象可以有与初始请求无关的生存期。

3) 需要支持取消操作。

4) 支持修改日志功能。这样当系统崩溃时,这些修改可以被重做一遍。

5) 需要支持事务操作。

六、总结

从面向对象的角度来看,是不完美的。命令角色仅仅包含一个方法,没有任何属性存在。这是将函数层面的人物提升到了类的层面。但不可否认的是:很成功的解决了许多问题,正如遍布在 Struts 那样。

上一页   |   返回目录   |   下一页

Author:

标签: 暂无
最后更新:2021-08-06

本书评论

取消回复

©2021 安居多伦多 - 版权所有

本站由 好事来 Hostlike.com 提供技术支持。