Java8函数式编程_8--设计和架构的原则

1,免责声明,本文大部分内容摘自《Java8函数式编程》。在这本书的基础上,根据自己的理解和网上一些博文,精简或者修改。本次分享的内容,只用于技术分享,不作为任何商业用途。当然这本书是非常值得一读,强烈建议买一本!
2,本次分享的样例代码均上传到github上,请点击这里

注意:本章所有的例子大多围绕 1.3 节介绍的案例展开(音乐)。

Lambda 表达式是对 Java 语言的一点简单改进,在 JDK 标准类库中,运行它的方式各种各样。但是大多数 Java 代码都不是由开发 JDK 的程序员写的, 而是像你我这样的普通程序员。为了最大限度发挥 Lambda 表达式的优势,大家需要将其引入已有代码中。作为一名职业 Java 程序员,Lambda 表达式没有什么特别的,和接口、类一样,它只是程序员工具箱中的一件新工具。

本章将探索如何使用 Lambda 表达式实现 SOLID原则,该原则是开发良好面向对象程序的准则。使用 Lambda 表达式,还能改进一些现有的设计模式,本章也会为大家简要介绍几个这样的例子。

本章旨在帮助大家写出优秀的程序,会给出一些良好的设计原则和模式,在此基础之上,就能开发出可维护且十分可靠的程序。我们不光会用到 JDK 提供的崭新类库,而且会教大家如何在自己的领域和应用程序中使用 Lambda 表达式。

主要内容如下:

  • 8.1 Lambda 表达式改变了设计模式
  • 8.2 使用 Lambda 表达式的领域专用语言
  • 8.3 使用 Lambda 表达式的 SOLID 原则
  • 8.4 进阶阅读

8.1 Lambda 表达式改变了设计模式

设计模式是一种设计思想,它是软件架构中解决通用问题的模板。如果碰到一个问题,并且恰好熟悉一个与之适应的模式,就能直接应用该模式来解决问题。从某种程度上来说,设计模式将解决特定问题的最佳实践途径固定了下来。

本章我们讨论的是如何使用 Lambda 表达式,让现有设计模式变得更好、更简单。Java 8 新特性是所有这些设计模式变化的推动因素。

8.1.1 命令者模式

命令者是一个对象,它封装了调用另一个方法的所有细节,命令者模式使用该对象,可以编写出根据运行期条件,顺序调用方法的一般化代码。命令者模式中有四个类参与其中,如图 8-1 所示。
在这里插入图片描述
// 图 8-1:命令者模式

  • 命令接收者 -> 执行实际任务。
  • 命令者 -> 封装了所有调用命令执行者的信息。
  • 发起者 -> 控制一个或多个命令的顺序和执行。
  • 客户端 -> 创建具体的命令者实例。

看一个命令者模式的具体例子,看看如何使用 Lambda 表达式改进该模式。假设有一个 GUI Editor组件,在上面可以执行 open、save 等一系列操作,如:例 8-1 所示。现在我们想实现 宏功能 ,也就是说,可以将一系列操作录制下来,以后作为一个操作执行,这就是我们的命令接收者。

// 例 8-1 文本编辑器可能具有的一般功能

public interface Editor {

	public void save(); 
	
	public void open(); 
	
	public void close();
}

Editor例子中,像 opensave 这样的操作称为 命令,我们需要一个统一的接口来概括这些不同的操作,我将这个接口叫作 Action,它代表了一个操作。所有的命令都要实现该接口 (例 8-2)。

// 例 8-2 所有操作均实现 Action 接口

public interface Action {
	public void perform(); 
}

现在让每个操作都实现该接口,这些类要做的只是在 Action 接口中调用 Editor 类中的一个方法。遵循恰当的命名规范,用类名代表操作,比如 save 方法对应 Save 类。例 8-3 和例 8-4 是定义好的命令对象。

// 例 8-3 save 操作代理给 Editor 方法

public class Save implements Action {

	private final Editor editor; 

	public Save(Editor editor) {
		this.editor = editor;
	}
	
	@Override
	public void perform() {
		editor.save();
	}
}

// 例 8-4 open 操作代理给 Editor 方法

public class Open implements Action {

	private final Editor editor;

	public Open(Editor editor) { 
		this.editor = editor;
	}
	
	@Override
	public void perform() {
		editor.open();
	}
}

现在可以实现宏类 Macro 了,然后一起运行。我们使用 List 保存操作序列,然后调用 forEach 方法按顺序执行每一个 Action,例 8-5 就是我们的命令发起者。

// 例 8-5 包含操作序列的宏,可按顺序执行操作

public class Macro {
	private final List<Action> actions;
	
	public Macro() {
		actions = new ArrayList<>();
	}
	
	public void record(Action action) {
		actions.add(action);
	}
	
	public void run() { 
		actions.forEach(Action::perform);
	}
}

在构建宏时,将每一个命令实例加入 Macro 对象的列表,然后运行宏,就会按顺序执行每一条命令。例 8-6 展示了如何在用户代码中使用 Macro 对象。

// 例 8-6 使用命令者模式构建宏

Macro macro = new Macro();
macro.record(new Open(editor)); 
macro.record(new Save(editor)); 
macro.record(new Close(editor)); 
macro.run();

Lambda 表达式能做点什么呢?事实上,所有的命令类,SaveOpen 都是 Lambda 表达式, 只是暂时藏在类的外壳下。它们是一些行为,我们通过创建类将它们在对象之间传递。Lambda 表达式特性可以让我们扔掉这些类,如:例 8-7。

// 例 8-7 使用 Lambda 表达式构建宏

Macro macro = new Macro(); 
macro.record(() -> editor.open()); 
macro.record(() -> editor.save()); 
macro.record(() -> editor.close()); 
macro.run(); 

事实上,如果意识到这些 Lambda 表达式的作用只是调用了一个方法,使用方法引用还能让问题变得更简单 (如例 8-8 所示)。

// 例 8-8 使用方法引用构建宏

Macro macro = new Macro(); 
macro.record(editor::open); 
macro.record(editor::save); 
macro.record(editor::close);
macro.run();  

8.1.2 策略模式

策略模式 能在运行时改变软件的算法行为。其主要思想是定义一个通用的问题,使用不同的算法来实现,然后将这些算法都封装在一个统一接口的背后。

文件压缩就是一个很好的例子。压缩文件的方式可以使用 zip 算法,也可以使用 gzip 算法,我们实现一个通用的 Compressor 类,能用任何一种算法压缩文件。

首先,为我们的策略定义 API (参见图 8-2),把它叫作 CompressionStrategy,每一种文件压缩算法都要实现该接口。该接口有一个 compress 方法,接受并返回一个 OutputStream 对象,返回的就是压缩后的 OutputStream (如例 8-9 所示)。
在这里插入图片描述
// 图 8-2:策略模式

// 例 8-9 定义压缩数据的策略接口

public interface CompressionStrategy { 
	public OutputStream compress(OutputStream data) throws IOException;
}

有两个类实现了该接口,分别代表 gzipzip 算法,使用 Java 内置的类实现 gzipzip算法 (例 8-10、8-11)。

// 例 8-10 使用 gzip 算法压缩数据

public class GzipCompressionStrategy implements CompressionStrategy {
	@Override
	public OutputStream compress(OutputStream data) throws IOException {
		return new GZIPOutputStream(data); 
	}
}

// 例 8-11 使用 zip 算法压缩数据

public class ZipCompressionStrategy implements CompressionStrategy {
	@Override
	public OutputStream compress(OutputStream data) throws IOException {
		return new ZipOutputStream(data); 
	}
}

现在可以动手实现 Compressor 类了,这里就是使用策略模式的地方。该类有一个 compress 方法,读入文件,压缩后输出。它的构造函数有一个 CompressionStrategy 参数,调用代码可以在运行期使用该参数决定使用哪种压缩策略,比如,可以等待用户输入选择(如例 8-12 所示)。

// 例 8-12 在构造类时提供压缩策略</

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值