在本博客中,我将说明如何使用Java 8 Lambda表达式以函数式编程方式实现命令模式 。 命令模式的目的是将请求封装为对象,从而为具有不同请求,队列或日志请求的客户端参数化,并支持相应的操作。 命令模式是一种编写通用代码的方法,该代码根据运行时决策对序列进行排序并执行方法。 此模式的参与者如下:
- 命令 –声明用于执行操作的接口。
- ConcreteCommand –定义Receiver对象和操作之间的绑定。
- 客户端 –创建ConcreteCommand实例并设置其接收者。
- 调用程序 –控制命令以执行请求。
- 接收器 –执行实际工作。
这些参与者之间的关系如下图所示:
让我们看一下命令模式的具体示例,看看如何用lambda表达式转换它。 假设我们有一个文件系统实用工具,该工具具有要调用的操作,例如打开文件,写入文件和关闭文件。 可以将其实现为宏功能-即可以记录的一系列操作,然后作为单个操作在以后运行。 这将是我们的接收者。
public interface FileSystemReceiver {void openFile();void writeFile();void closeFile();
}
每个操作(例如openFile和writefile )都是命令。 我们可以创建一个通用的命令界面以适合这些不同的操作。 我们将此接口称为“动作”,因为它表示在我们的域中执行单个动作。 这是我们所有命令对象都实现的接口。
public interface Action {public void perform();
}
现在让我们为每个操作实现Action接口。 所有这些类需要做的就是在FileReceiver上调用一个方法并将此调用包装到我们的Action接口中。 让我们以它们包装的操作命名它们,并使用适当的类命名约定-因此,openFile方法对应于一个名为OpenFile的类。
public class OpenFile implements Action {private final FileReceiver fileReceiver;public OpenFile(FileReceiver fileReceiver) {this.fileReceiver = fileReceiver;}public void perform() {fileReceiver.openFile();}}
现在,让我们实现Macro类。 宏由一系列可以依次调用的动作组成,它将充当调用者。 此类可以记录动作并集体运行它们。 我们可以将动作序列存储在List中,然后迭代获取每个动作以执行。
public class Macro {private final List actions;public Macro() {actions = new ArrayList<>();}public void record(Action action) {actions.add(action);}public void run() {actions.forEach(Action::perform);}
}
在填充宏时,我们可以将已记录的每个命令的实例添加到Macro对象。 现在简单地运行宏将依次调用每个命令。 这是我们的客户代码。
Macro macro = new Macro();
macro.record(new OpenFile(fileReceiver));
macro.record(new WriteFile(fileReceiver));
macro.record(new CloseFile(fileReceiver));
macro.run();
如果到目前为止您一直与我在一起,您会想知道lambda表达式在所有这些方面都适合。 实际上,我们所有的命令类,例如OpenFile,WriteFile和CloseFile,实际上只是希望突破包装的lambda表达式。 它们只是作为类传递的某些行为。 使用lambda表达式,整个模式变得更加简单,因为我们可以完全取消这些类。 让我们看看Macro类(客户端)如何使用lambda表达式代替命令类。
Macro macro = new Macro();
macro.record(() -> fileReceiver.openFile());
macro.record(() -> fileReceiver.writeFile());
macro.record(() -> fileReceiver.closeFile());
macro.run();
可以通过意识到这些lambda表达式中的每一个都在执行单个方法调用这一事实来进一步改善。 因此,方法引用可以直接使用。
Macro macro = new Macro();
macro.record(fileReceiver::openFile);
macro.record(fileReceiver::writeFile);
macro.record(fileReceiver::closeFile);
macro.run();
命令模式很容易扩展,可以在接收器中添加新的操作方法以创建新的命令实现,而无需更改客户端代码。 JDK中的Runnable接口(java.lang.Runnable)是使用Command模式的流行接口。 在这个博客中,我试图用Java 8 lambda表达式来表达命令模式。 通过使用lambda表达式,您会看到,所需的样板文件少得多,从而导致代码更简洁。
这篇文章的灵感来自Richard Warburton的文章使用带lambda表达式的命令模式 。
翻译自: https://www.javacodegeeks.com/2015/09/java-8-lambda-expression-for-design-patterns-command-design-pattern.html