从本篇开始进入到行为类型的设计模式。
一、行为类型的模式有一些先简略带过。比如很复杂的解释器模式(Interpreter),这个在实际应用中出现的较少。
二、职责链模式(Chain of Responsiblity),模式本身是很容易理解的,一系列的处理类遵循一样的接口,都有者其后继处理类successor和自己的处理方法。对于客户端调用,由职责链的第一个类开始执行处理方法,判断自己是否能够执行或者传给下一个successor.客户端和链上的任何一个类只需要知道把请求传给谁就好了,其它的情况都不了解。这样达到解耦的目的。
三、迭代器(Iterator)模式,这个已经根植于各类编程语言当中了。尤其是对于Hash这种存储结构,本身是hash桶的复杂形式,迭代器封装了遍历算法,让客户不用去关系存储结构的细节而方便的遍历集合对象。
四、是备忘录模式(Memento):如果一个对象的部分状态需要存储,以便以后恢复,良好的实践方式应该是,由源对象自己将这部分状态抽离出来形成一个备忘录对象,并由一个CareTaker对象保存起来,这个taker除了保存以外不能做其它任何操作。当源对象需要恢复状态时,taker将备忘录传递给源对象,由源对象自己完成恢复。 备忘录模式的核心意义是封装,所有的细节操作都在源对象之中完成,不对外暴露细节。其缺点在于,如果状态较多,会消耗很多的内存(感觉怎么保存也得消耗这些内存吧?)。实际使用中,可能遇到多个字段多种状态下的备份,那么应该给备忘录对象设置一个Map来统一存储这些状态,或者也有很多其它的实现方式。
五、Template模板方法模式。这也是一个非常常见的模式,最熟悉的无非大名鼎鼎的JDBCTemplate。所打开连接,准备sql,关闭连接,resultset等等的操作都提升到父类(抽象类,也可能是非抽象类)中,并形成方法骨架(模板)。子类只需要实现特定逻辑的那部分。 PS:Spring的JDBCTemplate就是一个非抽象形式,因为其使用模板方法模式的同时还使用了接口回调(在java回调的概念中有例子),我们使用匿名内部类实现接口的方式,替代了子类实现父类抽象方法的方式,是一个非常经典的模式。
六、观察者模式Visitor:是一个较少使用的方法。其适合的情况是:数据结构本身非常固定,不太改变。但是相应的数据行为、算法却经常变动。GoF说“如果你发现要用观察者时,那就确实是要用观察者了”。有需要的时候可以详细研究。
本篇的主题是Command命令模式:要理解命令模式我觉得应该先直接看命令模式的结构:
1.命令模式的核心是Command,即把客户的请求、命令、操作等,封装成一个Command–命令对象。一般来说,我们执行请求,命令,操作(统称为命令)都是直接调用命令的处理对象。但是在命令模式中,我们不会直接调用命令对象,甚至我们连命令的处理对象是谁都不知道(如果处理对象是在命令对象里内置的而不是通过客户端代码参数传递过来时)。我们要做的只是发起一个一个的命令。
2.命令模式的另一核心的Invoker调用者,既然客户不直接调用处理对象,那么总需要有一个地方来发起命令的处理。Invoker就是负责干这个的。其负责收集命令,存储命令,给命令排队,撤销,让命令开始执行。
总的说来,命令模式就是在普通的直接调用处理对象的情况下,加入了Invoker和Command这两个中间对象。用于统一的封装命令,统一的对所有命令进行维护,达到解耦的目的。下面是结构图:
现在我们再来看为什么要使用命令模式呢?
1.最基本的意义还是解耦,把发起一个命令和处理这个命令分隔成为不同的对象,同时加入invoker专门操纵命令,容易对命令进行队列维护,查询,记录日志,增删。要加入新的命令不会对原代码产生变动。
2.我们可以观察一下消息中间件,是不是有命令模式的味道在里面。生产者发送message给中间件,中间件负责收集和管理消息,并通知消费者消费消息。有了这个中间件的存在,我们能够很好的处理:异步调用的问题(排队);多线程的并发控制;在中间件中完成与回调类似的作用;统一的去处理各种类型各种性质的消息(日志管理),等等。可以想象,如果不解耦,这些代码将会是比较混乱的。
3.由于命令被抽取出来成为对象,那么当命令种类很多的时候,可能会出现子类数目的膨胀。
4.在实际开发中,应根据需要选择命令模式,复杂度低的逻辑,可以不使用或部分使用(只封装命令但没有invoker)。如对命令的管理要求较高时,或其它复杂情形,可以考虑使用。
class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void action(){
this.command.execute();
}
}
abstract class Command {
public abstract void execute();
}
class ConcreteCommand extends Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver){
this.receiver = receiver;
}
public void execute() {
this.receiver.doSomething();
}
}
class Receiver {
public void doSomething(){
System.out.println("接受者-业务逻辑处理");
}
}
public class Client {
public static void main(String[] args){
Receiver receiver = new Receiver();
//也可以吧receiver放在Command里内置初始化,这样客户端就完全不知道接收者的存在
Command command = new ConcreteCommand(receiver);
//客户端直接执行具体命令方式
command.execute();
//客户端通过调用者来执行命令
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.action();
}
}
本文详细解析命令模式的核心概念,包括命令、调用者和如何通过引入这两个中间对象来解耦发起命令和处理命令的过程。进一步讨论了命令模式在消息中间件、异步调用和多线程并发控制中的应用实例。文章还提到了命令模式可能带来的子类数目膨胀问题及在实际开发中的灵活应用策略。
1460

被折叠的 条评论
为什么被折叠?



