一、意图
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
二、适用性
(1)系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
(2)在不同的时刻指定、排列和执行请求。
(3)支持修改日志、撤销操作。
(4)系统需要将一组操作组合在一起,即支持宏命令。
三、组成
命令模式由以下角色组成:
—— 命令角色(Command):定义命令的接口,声明执行的方法。
——具体命令角色(Concrete Command):实现命令接口,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
——接收者角色(Receiver):负责具体实施和执行一个请求。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
—— 请求者(调用者)角色(Invoker):负责调用命令对象执行请求。
—— 客户角色(Client):创建一个具体命令对象并设定该命令对象的接收者。
四、结构
五、生活中的例子
(Order订单封装了请求)
六、简单实现
1.命令角色
- public interface Command
- {
- public void execute();
- }
public interface Command
{
public void execute();
}
2.具体命令角色
- public class ConcreteCommand implements Command
- {
- // 持有接收者的引用
- private Receiver receiver;
- public ConcreteCommand(Receiver receiver)
- {
- this.receiver = receiver;
- }
- @Override
- public void execute()//将命令的执行委托给接收者
- {
- receiver.doAction();
- }
- }
public class ConcreteCommand implements Command
{
// 持有接收者的引用
private Receiver receiver;
public ConcreteCommand(Receiver receiver)
{
this.receiver = receiver;
}
@Override
public void execute()//将命令的执行委托给接收者
{
receiver.doAction();
}
}
3.接收者角色
- public class Receiver
- {
- //接收者真正执行命令
- public void doAction()
- {
- System.out.println(”doAction”);
- }
- }
public class Receiver
{
//接收者真正执行命令
public void doAction()
{
System.out.println("doAction");
}
}
4.请求者(执行者)角色
- public class Invoker
- {
- //持有命令对象的引用,将动作委托给命令对象执行
- private Command command;
- public Invoker(Command command)
- {
- this.command = command;
- }
- public void doInvokerAction()
- {
- command.execute();
- }
- }
public class Invoker
{
//持有命令对象的引用,将动作委托给命令对象执行
private Command command;
public Invoker(Command command)
{
this.command = command;
}
public void doInvokerAction()
{
command.execute();
}
}
5.客户角色
- public class Client
- {
- public static void main(String[] args)
- {
- Receiver receiver = new Receiver();
- Command command = new ConcreteCommand(receiver);
- Invoker invoker = new Invoker(command);
- invoker.doInvokerAction();
- }
- }
public class Client
{
public static void main(String[] args)
{
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker(command);
invoker.doInvokerAction();
}
}
七、使用组合模式实现宏命令
- public class MacroCommand implements Command
- {
- Command[] commands;
- public MacroCommand(Command[] commands)
- {
- this.commands=commands;
- }
- @Override
- public void execute()
- {
- for(Command command : this.commands)
- command.execute();
- }
- @Override
- public void undo()
- {
- for(Command command : this.commands)
- command.undo();
- }
- }
public class MacroCommand implements Command
{
Command[] commands;
public MacroCommand(Command[] commands)
{
this.commands=commands;
}
@Override
public void execute()
{
for(Command command : this.commands)
command.execute();
}
@Override
public void undo()
{
for(Command command : this.commands)
command.undo();
}
}
使用时可以将MacroCommand当做普通命令使用。请求角色并不知道这是一个宏命令。
八、其他
1.命令模式将发出请求的对象和执行请求的对象解耦,两者之间通过命令对象进行沟通。将请求封装成对象,这个对象可以被储存、传递、调用。
2.命令模式降低了对象之间的耦合度,使得我们 可以很轻松地加入新的命令、根据组合的优点轻松设计宏命令等,但是不足之处就是会导致大量具体命令类的产生。
3.实现命令的撤销:在Command中加入undo()方法,在undo()方法中调用receiver的相关方法,Invoker调用Command的undo()方法实现撤销。当请求者(调用者)Invoker持有多个命令对象时,需要在Invoker中加入一个Command引用用来记录最后执行的命令以实现命令撤销。如果想要实现多层次的撤销操作,则在Invoker中就需要使用一个堆栈记录操作过程中的每一个命令,然后从堆栈中取出最上层的命令实现撤销。
4.宏命令的实现使用到了组合模式,可以一次执行一组命令,Invoker并不知道这是一个单一的命令还是宏命令,宏命令更加灵活,更优雅。
5.队列请求功能:工作队列对象并不在乎命令对象具体是干什么的,它只是在队列中取出Command命令对象然后调用其execute()方法。
6.日志请求功能:当每个命令被执行时,可以将Command命令对象存储在磁盘上(序列化等方法),需要时从磁盘上加载命令对象。(在Command接口中加入store()、load()方法)
7.在实际操作中,可省略接收者角色,让命令对象直接实现请求而不是将工作委托给接收者。
转载请注明出处:http://blog.csdn.net/jialinqiang/article/details/8752111