一、简介
Command pattern是一套基于Spring Framework ,以Use Case为中心的框架。它糅合了几种经典的JavaEE设计模式,使应用开发者在实现Use Case时,能够更专注于商业逻辑本身。
结构图:
整个业务层都是用Spring框架来配置的。Spring是一种轻量的IoC的框架,使用Spring能够最大程度上保证业务逻辑不被污染
表现层调用业务逻辑层的流程图:
二、具体流程
1. 客户端
如何调用一个业务逻辑呢?对于业务逻辑的调用者(通常是表现层),完全不用关心这个业务逻辑是如何实现的。对客户端而言,它只能看到command dispatcher,如下图:
对需要调用业务操作的Web层组件,其内聚了一个CommandDispatcher,通过该dispatcher来完成业务的委派,但是这个commandDispatcher就是一个Bean,它存在于Spring容器之中(可以参考web层的模块ioc)。缺点在于web层被command所侵入,并且与业务实现在一定程度上发生了耦合。
步骤:
a)创建一个Command,填上业务逻辑所需要的参数。
b)将Command对象传递给CommandDispatcher,这样就完成了业务逻辑的调用。
c)如果需要,可以取得业务逻辑的返回结果。
// Step 1. 装配一个command, // command名称为"userCommand","userCommand"中有许多有关user的子命令, // 而"registerUser"是其中的一个子命令。(子命令参数是可选的) Command command = new CommandSupport("userCommand", "registerUser"); commandName.getParameters().put("name", "michael"); commandName.getParameters().put("password", "helloworld"); commandName.getParameters().put("email", "[email protected]"); // Step 2. 调用业务逻辑 Result result = getDispatcher().execute(command); // Step 3. 处理返回结果 if (result.isSuccess()) { User user = (User) result.getModels().get("user"); // 通常这类操作会返回数据库所创建的sequence ID。 int id = user.getId(); ... } else { ResultCode errorCode = result.getResultCode(); if (errorCode == UserResultCode.USER_ALREADY_EXISTS) { ... } ... }
服务端,它也不需要了解客户端的情况。服务端要做的,无非是从系统接收command的请求,然后执行相应的业务逻辑而已。
步骤:
a)创建ApplicationObject(即AO)。
实现ApplicationObject接口,但建议从ApplicationObjectSupport继承
public class LoginAO extends ApplicationObjectSupport { }
b)执行
类似于WebX中的action,AO可以根据command中的event参数来自动调用相应的方法,例如 new CommandSupport("loginAO", "login"),那么,只要实现下面的方法即可
public Result doLogin() { Account user = userManager.login(userId, password); Result result = new ResultSupport(); if (user == null) { result.setSuccess(false); result.setResultCode( LoginResultCode.INVALID_USER_OR_PASSWORD); } else { result.setDefaultModel("user", user); } return result; }如果没有提供event参数,或未匹配event,那么默认的doPerform()方法将被执行
3. CommandDispatcher 实现
CommandDispatcher是一个“分发器”。它的功能就是根据command的名字找到相应的业务逻辑对象,并执行之。每一个业务逻辑对象对应一个或一组相关的use case。例如:在用户管理系统中,用户的创建、删除、修改等操作可以看作一个use case,因而我们可以写一个业务逻辑对象——“UserManagementAO”——来处理这个use case。“AO”是“ApplicationObject”的缩写,每一个AO必须实现ApplicationObject接口。
CommandDispatcher有多种实现,以适应多种需要:
序号 |
CommandDispatcher的实现 |
说明 |
1. |
Stateless Session Bean (CommandDispatcherBean)
|
使用Stateless Session Bean来分发Command。该实现允许进行分布式的商业逻辑调用。 |
2. |
Message-driven Bean (CommandDispatcherClient) |
通过Message-driven Bean来分发Command,通过JMS来发送Command请求。该实现允许进行异步的商业逻辑调用。 |
3. |
Plain Javabean (CommandDispatcherLogic) |
通过普通的Javabean来分发Command。这个实现非常适合在非EJB的环境下调用商业逻辑。 |
4. |
NOOP (CommandDispatcherNoop) |
不做任何事情的分发器。这个实现非常适合在程序的开发阶段,用来调试程序。或者当商业逻辑还未开发完成时,调用者可以利用该分发器来“调用”商业逻辑,以便调用者的代码可以被顺利地开发。 |
5. |
Selector (CommandDispatcherSelector) |
该分发器可根据Command的内容来自动先择合适的其它CommandDispatcher。这样,我们就可以更方便地控制CommandDispatcher的行为。例如,在调用者完全不知情的情况下,将某个Command的处理转变为利用Message-driven bean来异步处理。 |
尽管有这么多种CommandDispatcher的实现,但是表现层完全不用了解这些细节。所有的CommandDispatcher都是通过spring来配置的
4. 小结
Command Pattern是基于request-response的模式。客户端创建command,服务端响应command并返回结果给客户端 —— 类似WEB层的模式。而客户端和服务端是通过command dispatcher来连接的。
这种模式有什么好处呢?
最大的好处,就是客户端和服务端完全分离。无论是Web-tier还是Biz-tier都不用了解command分发的细节 —— 这些细节对代码是透明的。
其次,所有的CommandDispatcher都是通过spring来配置的,因此也很容易创建新的CommandDispatcher模式。目前已经支持同步、异步等操作。
那么,这种模式有什么缺点呢?任何设计模式都有适用的场合,也有不利的一面。Command Pattern也不例外。
这种模式最大的缺点是,没有一种统一的方法,可以知道业务逻辑层所需要的参数个数、类型,同样也很难知道返回值的数量和类型。这样会增加客户端/服务端程序员交流的成本。