本文共 2191 字,大约阅读时间需要 7 分钟。
命令模式(Commond Pattern):将来自客户端的请求封装为一个对象,无需了解这个请求激活的动作或有关接受这个请求的处理细节。命令模式的根本目的在于将“请求者”与“实现者”之间解耦。
其实命令模式和其他许多设计模式一样,就是在请求者和实现者中间加一个中间人的角色,来达到解除耦合的目的。通过对中间人的特殊设置,从而形成不同的设计模式,命令模式也不例外。命令模式正是通过一个中间的命令者角色完成请求与实现之间的解耦。
命令模式分为三部分,调用者、接收者和命令类,其实质是在命令发出者和命令接受者之间增加第三方来实现解耦,下面来使用实例来说明。
需求:使用命令模式完成邮局案例,需要一个发件人、邮局、收件人三种实体对象。发件人投递信件给邮局,邮局需要做的是将信件发给收件人,自始至终,我们都没有让发件人和收件人进行直接通信,也就是说,命令的调用者和接收者是没有联系的,完全通过邮局这个中间人来联系。
案例类图:
首先创建一个“IReceiver”收件人接口,其中只有一个读取信件的readMail方法:
/* * 功能:命令模式,接收者 * 信件接收者 */public interface IReceiver { public void readMail(String message);}
接下来,我们创建收件人类,并实现收件人接口:
/* * 功能:接收者实现类 */public class ReceiverImp implements IReceiver { @Override public void readMail(String message) { System.out.println("收件人读取信息:"+message); }}
创建邮局接口IPost,该接口中定义发送信件的方法sendMail:
/* * 功能:邮局接口,即命令接口 * */public interface IPost { public void sendMail(String message);}
创建邮局实现类,因为邮局需要将信件转发给收件人,所以要保持对收件人的引用:
/* * 功能:邮局接口实现类 */public class IPostImp implements IPost { // 保持对收件人的引用 private final IReceiver receiver; //通过构造方法传入 public IPostImp(IReceiver receiver){ this.receiver = receiver; } //具体发送功能 @Override public void sendMail(String message) { System.out.println("信息已经发送给收件人!"); receiver.readMail(message); }}
接下来,我们来创建发送者,因为发送者需要将信件放到邮局,所以要保持对邮局的引用,我们通过构造方法来传入这个引用:
/* * 功能:发送者,即命令调用者 */public class Invoker { //保留邮局引用 private IPost ipost; //设置邮局对象实例 public void setPost(IPost ipost){ this.ipost=ipost; } //发件人发送信息 public void postMail(String message){ System.out.println("发信人开始投递邮件给邮局。。。"); ipost.sendMail(message); }}
接下来就是我们的测试类(客户端)了,创建发件人、收件人、邮局实例,然后进行发邮件:
/* * 功能:测试类 */public class Test { public static void main(String[] args) { Invoker in = new Invoker(); ReceiverImp receiver = new ReceiverImp(); IPostImp post = new IPostImp(receiver); in.setPost(post); in.postMail("我来了!"); }}
信件通过邮局发送,而发件人和收件人之间却没有任何联系,这就是命令模式的应用,也是符合迪米特法则(最少知识原则)的,即两个实体之间如果没有必要进行联系的话,那就尽量不要让它们进行直接联系,而是采取中间人的方式对其进行解耦。
总结:命令模式中,精髓就是请求的启动者发送命令请求给具体命令,由具体命令负责发送命令消息给命令的接收者,具体命令就是模式模式中的中间人角色。
命令模式的适用场合:
抽象出待执行的动作以参数化某对象。类似于过程设计中的回调机制,而命令模式正式回调机制的一个面向对象的替代品;
在不同的时刻指定、排列和执行请求;
需要支持可撤销的操作;
需要支持修改日志功能。这样当系统崩溃时,这些修改可以被重做一遍;
需要支持事务系统。