本文是一篇《Java 8实战》的阅读笔记,阅读大约需要5分钟。

有点标题党,但是这确实是我最近使用Lambda表达式的感受。设计模式是过去的一些好的经验和套路的总结,但是好的语言特性可以让开发者不去考虑这些设计模式。面向对象常见的设计模式有策略模式、模板方法、观察者模式、责任链模式以及工厂模式,使用Lambda表达式(函数式编程思维)有助于避免面向对象开发中的那些固定代码。下面我们挑选了策略模式和职责链模式两个案例进行分析。

案例1:策略模式

当我们解决一个问题有不同的解法的时候,又不希望客户感知到这些解法的细节,这种情况下适合使用策略模式。策略模式包括三个部分:

  • 解决问题的算法(上图中的Strategy);
  • 一个或多个该类算法的具体实现(上图中的ConcreteStrategyA、ConcreteStrategyB和ConcreteStrategyC)
  • 一个或多个客户使用场景(上图中的ClientContext)

面向对象思路

首先定义策略接口,表示排序策略:

public interface ValidationStrategy {boolean execute(String s);
}

然后定义具体的实现类(即不同的排序算法):

public class IsAllLowerCase implements ValidationStrategy {@Overridepublic boolean execute(String s) {return s.matches("[a-z]+");}
}public class IsNumberic implements ValidationStrategy {@Overridepublic boolean execute(String s) {return s.matches("\\d+");}
}

最后定义客户使用场景,代码如下图所示。Validator是为客户提供服务时使用的上下文环境,每个Valiator对象中都封装了具体的Strategy对象,在实际工作中,我们可以通过更换具体的Strategy对象来进行客户服务的升级,而且不需要让客户进行升级。

public class Validator {private final ValidationStrategy strategy;public Validator(ValidationStrategy strategy) {this.strategy = strategy;}/*** 给客户的接口*/public boolean validate(String s) {return strategy.execute(s);}
}public class ClientTestDrive {public static void main(String[] args) {Validator numbericValidator = new Validator(new IsNumberic());boolean res1 = numbericValidator.validate("7780");System.out.println(res1);Validator lowerCaseValidator = new Validator(new IsAllLowerCase());boolean res2 = lowerCaseValidator.validate("aaaddd");System.out.println(res2);}
}

函数式编程思路

如果使用Lambda表达式考虑,你会发现ValidationStrategy就是一个函数接口(还与Predicate具有同样的函数描述),那么就不需要定义上面那些实现类了,可以直接用下面的代码替换,原因是Lambda表达式内部已经对这些类进行了一定的封装。

public class ClientTestDrive {public static void main(String[] args) {Validator numbericValidator = new Validator((String s) -> s.matches("\\d+"));boolean res1 = numbericValidator.validate("7789");System.out.println(res1);Validator lowerCaseValidator = new Validator((String s) -> s.matches("[a-z]+"));boolean res2 = lowerCaseValidator.validate("aaaddd");System.out.println(res2);}
}

案例2:责任链模式

在某些场景下,需要对一个对象做一系列的工作,这些工作分别是由不同的类完成的,这时候就比较适合使用责任链模式。责任链模式的主要组成部分包括三个:

  • 管理操作序列的抽象类,在该抽象类里有会有一个对象记录当前对象的后继操作对象;
  • 一些具体的操作对象,这些操作对象会以一个链表的形式组织起来
  • 一个使用该模式的客户端组件,该组件只需要跟一个组件打交道就好,不需要跟很多个操作对象耦合在一起。

面向对象思路

首先看下我们这里定义了一个抽象类ProcessingObject,其中successor字段用于管理该对象的后继操作对象;handle接口作为对外提供服务的接口;handleWork作为实际处理对象的操作方法。

public abstract class ProcessingObject<T> {protected ProcessingObject<T> successor;public void setSuccessor(ProcessingObject<T> successor) {this.successor = successor;}public T handler(T input) {T r = handleWork(input);if (successor != null) {return successor.handler(r);}return r;}abstract protected T handleWork(T input);
}

接下来可以定义两个具体的操作对象,如下面代码所示。PS:这里《Java 8实战》书中用的是replaceAll方法是不太合适的,这个点可以参考我们之前的文章——020:举几个String的API以及案例。

public class HeaderTextProcessing extends ProcessingObject<String> {@Overrideprotected String handleWork(String input) {return "From Raoul, Mario and Alan: " + input;}
}public class SpellCheckerProcessing extends ProcessingObject<String> {@Overrideprotected String handleWork(String input) {return input.replace("labda", "lambda");}
}

最后,你就可以在Client中将这上面两个具体的操作类对象构成一个操作序列,参见下面的代码:

public class Client {public static void main(String[] args) {ProcessingObject<String> p1 = new HeaderTextProcessing();ProcessingObject<String> p2 = new SpellCheckerProcessing();p1.setSuccessor(p2);String result = p1.handler("Aren't labdas really sexy?!!");System.out.println(result);}
}

函数式编程思路

如果使用函数式编程思维,那么职责链模式就直接了——y=f(x)和z=g(x)这两个方法都是要对x做处理,那么如果将这两个函数组合在一起,就会形成r=f(g(x))的情况,也就是可以使用Lambda表达式中的addThen来串联起多个处理过程。

public class ClientWithLambda {public static void main(String[] args) {UnaryOperator<String> headerProcessing = (String text) -> "From Raoul, Mario and Alan: " + text;UnaryOperator<String> spellCheckProcessing = (String text) -> text.replace("labda", "lambda");Function<String, String> function = headerProcessing.andThen(spellCheckProcessing);String result = function.apply("Aren't labdas really sexy?!!");System.out.println(result);UnaryOperator<String> hhhhhProcessing = (String text) -> text.concat("hhhh");Function<String, String> function1 = function.andThen(hhhhhProcessing);String result1 = function1.apply("Aren't labdas really sexy?!!");System.out.println(result1);}
}

上面是利用Java原生的Lambda表达式实现的职责链模式,我们也可以使用前面一篇文章——vavr:让你像写Scala一样写Java中介绍过的vavr库来实现,代码如下所示:

public class ClientWithVavr {public static void main(String[] args) {Function1<String, String> headerProcessing = (String text) -> "From Raoul, Mario and Alan: " + text;Function1<String, String> specllCheckProcessing = (String text) -> text.replace("labda", "lambda");Function1<String, String> function = headerProcessing.compose(specllCheckProcessing);String result = function.apply("Aren't labdas really sexy?!!");System.out.println(result);}
}

总结

可以看出,函数式编程思维跟面向对象编程思维的思考方式是不同的,表达力更强,因此,作为开发者是时候认真学习下函数式编程思维了,作为Java开发者,我准备先从Lambda表达式开始学起,然后尝试学习下Scala或Kotlin两门语言中的函数式编程特性。

参考资料

  1. 《Java编程实战》
  2. 《设计模式之禅》

本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。

转载于:https://www.cnblogs.com/javaadu/p/11148006.html

函数式编程让你忘记设计模式相关推荐

  1. 面向java开发者的函数式编程_函数式编程让你忘记设计模式

    本文是一篇<Java 8实战>的阅读笔记,阅读大约需要5分钟. 有点标题党,但是这确实是我最近使用Lambda表达式的感受.设计模式是过去的一些好的经验和套路的总结,但是好的语言特性可以让 ...

  2. 函数式编程会取代GoF设计模式吗?

    自从我去年开始学习F#和OCaml以来,我已经阅读了大量文章,这些文章坚持认为设计模式(尤其是Java语言)是命令式语言中缺少功能的变通方法. 我发现一篇文章提出了相当有力的主张 : 我遇到的大多数人 ...

  3. 函数式编程4-高阶函数

    以其他函数作为参数的函数 本章的所有代码,均在github.com/antgod/func- 关于传递函数的思考 max 在很多编程语言的核心库,都包含一个叫做max的函数.包括underscore也 ...

  4. elm具体实现过程_函数式编程中的战斗机(二)---elm语言MUV设计模式应用实例...

    1 elm语言设计模式的特点 1.1 面向对象设计模式的特点 每种编程语言都有其独特的语法和优缺点,从而导致与众不同的设计模式和固定架构.面向对象编程因其竭力接近和模拟现实世界的多态和继承,导致面向对 ...

  5. 用 Kotlin 的函数式编程 替代 GOF 设计模式

    用 Kotlin 的函数式编程 替代 GOF 设计模式 函数式编程(FP) <Kotlin极简教程>正式上架: 点击这里 > 去京东商城购买阅读 点击这里 > 去天猫商城购买阅 ...

  6. Java 设计模式最佳实践:一、从面向对象到函数式编程

    原文:Design Patterns and Best Practices in Java 协议:CC BY-NC-SA 4.0 贡献者:飞龙 本文来自[ApacheCN Java 译文集],采用译后 ...

  7. 聊一聊C++设计模式、函数式编程等

    文章目录 1.variant技巧 2.std::enable_if_t用法 (1)C++模板 SFINAE (2)C++模板 匿名类型参数 (3)enable_if (4)enable_if_t (5 ...

  8. 函数式编程中的战斗机(二) --运用elm语言MUV设计模式做一个简单的应用实例

    @函数式编程中的战斗机(二) -运用elm语言MUV设计模式做一个简单的应用实例 1 elm语言设计模式的特点 1.1 面向对象设计模式的特点 每种编程语言都有其独特的语法和优缺点,从而导致与众不同的 ...

  9. Java 函数式编程入门

    Java 函数式编程入门 函数式编程实战 改进 完整代码   像 JavaScript 这种语言很早就支持闭包了,虽然 C++ 很早就有了函数指针,Java 也很早就提供了反射中的 Method 类, ...

最新文章

  1. unity shader 纹理透明效果
  2. 半监督学习技术在金融文本分类上的实践
  3. 最新的.NET Framework聚焦于改进可访问性
  4. 【Python】pdf2image模块+poppler将PDF转换为图片
  5. 数位 dp 最低位最高位之差绝对值大于2_面试必备——手撕代码(2)“买卖股票的最佳时机”...
  6. python基础 - 字符串与列表的基本操作方法
  7. html5文字布局排版欣赏,用文字作为主体排版的15个网页设计案例
  8. git add 后git reset --hard xxx的代码丢失,代码如何找回
  9. [转]2009年河南省高考零分作文:兔子,你就是一个傻B
  10. M1 电脑可以体验Windows11系统吗?M1 MAC安装win11详细教程(附图解)
  11. 利用Python快速绘制海报级别地图
  12. Python numpy.corrcoef函数方法的使用
  13. Android NNAPI - Paddle - TensorFlow - PyTorch ArgMax and ArgMin 的定义与计算过程
  14. c语言 截止频率6低通滤波器,C语言 低通滤波器带通滤波器高通滤波器.doc
  15. Selenium打开浏览器的方式总结
  16. C语言两个自增相加,C语言前自增与后自增
  17. bearychat和trello的协同工作
  18. js 正则是否包含某些字符串_js 正则包含字符
  19. 怀旧服 服务器 维护 怪物,魔兽世界怀旧服问答_怀旧服官方问答要点_3DM网游
  20. 荣耀7android正在升级,手机资讯导报:华为+荣耀7款老爷机齐升安卓8.0最近两年全覆盖...

热门文章

  1. 数据结构之并查集:并查集解决案例, Python——21
  2. 二十六、PHP框架Laravel学习笔记——模型的一对多关联
  3. LeetCode 1642. 可以到达的最远建筑(二分查找 / 优先队列贪心)
  4. LeetCode 1254. 统计封闭岛屿的数目(图的BFS DFS)
  5. oracle如何检查是否rac,Oracle RAC 状态检查
  6. postek二次开发_20190626_二次开发BarTender打印机_C#代码_一边读取TID_一边打印_打印机POSTEK...
  7. 电压压力蕊片_一文让你知道什么是压力变送器
  8. springboot整合kafka_springboot整合kafka实现消息的发送消费
  9. 文件标识符无效。使用 fopen 生成有效的文件标识符。_「存储架构」块存储、文件存储和对象存储(第1节)...
  10. ACL’22 | 为大模型定制的数据增强方法FlipDA,屠榜六大NLU 数据集!