9.3.5 命令模式
考虑这样一种场景:某个方法需要完成某一个功能,完成这个功能的大部分步骤已经确定了,但可能有少量具体步骤无法确定,必须等到执行该方法时才可以确定。具体一点:假设有个方法需要遍历某个数组的数组元素,但无法确定在遍历数组元素时如何处理这些元素,需要在调用该方法时指定具体的处理行为。
这个要求看起来有点奇怪:这个方法不仅要求参数可以变化,甚至要求方法执行体的代码也可以变化,需要能把“处理行为”作为一个参数传入该方法。
在某些编程语言(如Ruby
、Perl
等)中,确实允许传入一个代码块作为参数。从Java8
开始支持的Lambda
表达式也可以实现这种功能.
对于这样的需求,要求把”处理行为”作为参数传入该方法,而”处理行为”用编程来实现就是段代码。那如何把这段代码传入某个方法呢?在Java
语言中,类才是一等公民,方法也不能独立存在,所以实际传入该方法的应该是一个对象,该对象通常是某个接口的匿名实现类的实例,该接口通常被称为命令接口,这种设计方式也被称为命令模式。
程序示例
1 | E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\Command |
下面的程序先定义一个ProcessArray
类,该类里包含一个each
方法用于处理数组,但具体如何处理暂时不能确定,所以each()
方法里定义了一个Command
参数。
1 | public class ProcessArray |
上面定义each()
方法时,指定了一个Command
形参,这个Command
接口用于定义一个process()
方法,该方法用于封装对数组的”处理行为”。下面是该Command
接口代码。
1 | public interface Command |
上面的Command
接口里定义了一个process()
方法,这个方法用于封装”处理行为”,但这个方法没有方法体—因为现在还无法确定这个处理行为。
下面是主程序调用ProcessArray
对象each()
方法的程序。
1 | public class CommandTest |
正如上面的程序中两段粗体字代码所示,程序两次调用ProcessArray
对象的each()
方法来处理数组对象,每次调用each()
方法时传入不同的Command
匿名实现类的实例,不同的Command
实例封装了不同的”处理行为”。
运行上面程序,将看到如下结果。
1 | 迭代输出目标数组的元素:3 |
上面的运行结果显示了两次不同处理行为的结果,也就实现了process()
方法和”处理行为”的分离,两次不同的处理行为分别由两个不同的Command
对象来提供。
Java8
新增了Lambda
表达式功能,Java8
允许使用Lambda
表达式创建函数式接口的实例。
什么是函数式接口
所谓函数式接口,指的是只包含一个抽象方法的接口。上面程序中的Command
接口就是函数式接口。因此CommandTest
可改写为如下形式
1 | public class LambdaTest |
理解了这个命令模式后,相信读者对Spring
框架中HibernateTemplate
的execute
方法找到了一点感觉, HibernateTemplate
使用了execute()
方法弥补了HibernateTemplate
的不足,该方法需要接受一个HibernateCallback
接口,该接口的代码如下:
1 | // 定义一个`HibernateCallback`接口,该接口封装持久化处理行为 |
上面的HibernateCallback
接口就是一个典型的Command
接口,一个HibernateCallback
对象封装了自定义的持久化处理
对HibernateTemplate
而言,大部分持久化操作都可通过一个方法来实现, HibernateTemplate
对象简化了Hibernate
的持久化操作,但丢失了使用Hibernate
持久化操作的灵活性.
通过HibernateCallback
就可以弥补HibernateTemplate
灵活性不足的缺点,当调用HibernateTemplate
的execute()
方法时,传入Hibernate Callback
对象的dolnhibernateo
方法就是自定义的持久化处理—即将自定义的持久化处理传入了execute()
方法。下面的代码片段使用Lambda
表达式来实现该功能。
1 | List list=getHibernateTemplate() |
上面程序中的粗体字代码块将直接传给HibernatTemplate
,HibernatTemplate
将直接使用该代码块来执行持久化查询,并将查询得到的结果作为execute()
方法的返回值。
原文链接: 9.3.5 命令模式