基于lambda简化设计模式

写在文章开头

本文将演示基于函数式编程的理念,优化设计模式中繁琐的模板化编码开发,以保证用尽可能少的代码做尽可能多的事,希望对你有帮助。

在这里插入图片描述

Hi,我是 sharkChili ,是个不断在硬核技术上作死的 java coder ,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述

详解lambda重构设计模式思路

策略模式

不同的业务对于字符串有着不同的匹配规则,例如:长度是否大于10、是否全是大小、是否是电话号码等,为了保证规则的复用,我们通常会采用策略模式封装这些规则:

在这里插入图片描述

对应的我们给出策略封装的接口定义:

/*** 定义策略模式的接口*/
public interface ValidationStrategy {/*** 校验该字符串是否符合要求,若符合则返回true* @param str* @return*/boolean execute(String str);
}

后续让我们的规则校验器将这个抽象的校验规则接口聚合进来,如此我们就可以按照需求传入对应的校验规则策略strategy

public class Validator {//将校验规则聚合进来private ValidationStrategy strategy;public Validator() {}public Validator(ValidationStrategy strategy) {this.strategy = strategy;}//基于聚合的strategy校验字符串strpublic boolean validate(String str) {return strategy.execute(str);}
}

以下便是判断字符串是否全小写的校验规则实现:

/*** 判断是否全为小写*/
public class IsAllLowerCase implements ValidationStrategy {@Overridepublic boolean execute(String str) {return str.matches("[a-z]+");}
}

完成后我们就可以将IsAllLowerCase实例化并传入校验器Validator 中进行使用了:

//校验是否全是小写
Validator validator = new Validator(new IsAllLowerCase());System.out.println(validator.validate("abc"));//true

可以看到我们的校验规则基本上一行就可以搞定,为了这仅有的一行逻辑实现而编写大量的前置模板实在繁琐,对此我们不妨基于之前所介绍的函数式编程的思路分析以下,我们的ValidationStrategy本质上就只有一个抽象接口,所以它完全可以被认定为一个函数式接口,所以我们不妨将FunctionalInterface这个注解加上:

@FunctionalInterface
public interface ValidationStrategy {/*** 校验该字符串是否符合要求,若符合则返回true* @param str* @return*/boolean execute(String str);
}

参考其抽象方法,我们可以看到入参为String,返回值为boolean,由此推出函数描述符为(String)->boolean,我们以上文全小写规则为例,按照这个函数描述符的规则,我们的表达式就是:(s)->s.matches("[a-z]+"),是不是简化了许多呢?

在这里插入图片描述

对应的我们给出简化后的代码:

 //校验是否全是小写Validator validator = new Validator((s)->s.matches("[a-z]+"));System.out.println(validator.validate("abc"));

模板方法

模板方法的理念是对于固化模板自实现,然后将个性化业务下沉到不同业务场景自行开发,我们以银行找到会员为例,其大体步骤为:

  1. 查询会员信息(固定)。
  2. 招待会员。(不同银行流程不同)。

在这里插入图片描述

基于这个需求我们得出这样一个抽象类:

public abstract class Banking {public void processCustomer(int id) {//查询会员信息String customer = getCustomerWithId(id);//招待会员makeCustomerHappy(customer);}private String getCustomerWithId(int id) {return "user-"+id;}//不同银行有不同的实现protected abstract void makeCustomerHappy(String customer);
}

对应的我们给出BankingA 的招待逻辑:

public class BankingA extends Banking {@Overrideprotected void makeCustomerHappy(String customer) {System.out.println("请"+customer+"吃饭,并为其办理业务");}
}

对应我们给出使用代码和输出结果:

Banking bankingA = new BankingA();bankingA.processCustomer(1);//输出请user-1吃饭,并为其办理业务

还是一样的问题,为了仅仅一段简单的输出去适配模板方法从而编写出一段繁琐的代码,很明显是需求简化的。

分析抽象方法makeCustomerHappy的定义,要求传入String返回void,由此我们按照函数式编程的套路得出可能要用到的函数式接口的函数描述符为:(String)->Void,于是我们得到了一个JDK8自带的接口Consumer,它的函数签名为(T)->Void,注意这个T是泛型,所以我们完全可以将String类等价代入:

在这里插入图片描述

这里我们也给出Consumer的源码,读者可自行查阅:

@FunctionalInterface
public interface Consumer<T> {//......void accept(T t);}

对此我们将抽象类Banking 加以改造,将抽象方法makeCustomerHappy改为Consumer接口:

public class Banking {public void processCustomer(int id, Consumer<String> makeCustomerHappy) {//查询会员信息String customer = getCustomerWithId(id);//招待会员makeCustomerHappy.accept(customer);}private String getCustomerWithId(int id) {return "user-"+id;}}

于是我们的代码就简化成了下面这样:

 Banking bankingA = new BankingA();bankingA.processCustomer(1, (s) -> System.out.println("请" + s + "吃饭,并为其办理业务"));

观察者模式

观察者模式算是最经典也最好理解的设计模式,观察者只需将自己注册到感兴趣的主题上,一旦有主题更新就会及时通知观察者处理该消息:

在这里插入图片描述

基于这种设计模式的理念,我们给出观察者的接口的定义:

/*** 观察者*/
public interface Observer {//主题有更新调用该方法通知观察者void inform(String msg);
}

然后就是主题接口的定义:

public interface Subject {//注册观察者void registerObserver(Observer observer);//通知消息给所有观察者void notifyObserver();
}

对此我们给出一个观察者的实现:

public class Observer1 implements Observer {@Overridepublic void inform(String msg) {System.out.println("观察者1收到通知,内容为:" + msg);}
}

最后就是主题类的实现,我们将观察者聚合,如果观察者对SubJect1 感兴趣,则通过registerObserver完成注册,一旦主题要发布新消息就可以通过notifyObserver及时通知每一个订阅者:

public class SubJect1 implements Subject {private String msg;public SubJect1(String msg) {this.msg = msg;}private List<Observer> observerList = new ArrayList<>();//将观察者添加到订阅者列表@Overridepublic void registerObserver(Observer observer) {observerList.add(observer);}//有新消息通知订阅列表的所有用户@Overridepublic void notifyObserver() {observerList.forEach(o -> o.inform(msg));}

测试代码和对应输出结果如下所示:

public static void main(String[] args) {SubJect1 subJect1 = new SubJect1("请大家学习《基于lambda简化设计模式》");//注册订阅者subJect1.registerObserver(new Observer1());//主题发起通知subJect1.notifyObserver();//观察者1收到通知,内容为:请大家学习《基于lambda简化设计模式》}

每一个观察都是一行代码,为了这一行创建一个类显得有些繁琐,仔细查看registerObserver方法的定义我们可以得出该方法的签名为Observer->Void,由此我们可以推导出对应的lambda表达式:

在这里插入图片描述

由此我们可以直接将上述Observer1的代码简化为lambda表达式,对应代码示例如下:

 subJect1.registerObserver(s -> System.out.println("观察者1收到消息" + s));

责任链模式

责任链在Spring或者Netty这种大型框架中非常常见,它通过链式关系顺序的调用处理器处理当前业务数据,举个例子,我们希望字符串被对象1处理完成之后要转交给对象2处理,并且我们后续可能还会交给更多的对象处理,通过对需求的梳理和抽象,这个功能可以通过责任链模式来实现。

在这里插入图片描述

首先声明责任链上每一个处理器的抽象类,考虑到通用性笔者将这个类的入参设置为泛型,并且公共方法handle的步骤为:

  1. 调用自己的handWork处理输入数据,handWork交给实现类自行编写。
  2. successor不为空,则将处理结果交给下一个处理器处理,由此构成一条处理链。
public abstract class ProcessingObject<T> {/*** 下一个处理器*/private ProcessingObject<T> successor;public ProcessingObject<T> getSuccessor() {return successor;}public void setSuccessor(ProcessingObject<T> successor) {this.successor = successor;}public T handle(T input) {//先自己处理完,如果有后继责任链,则交给后面的责任链处理,递归下去T t = handWork(input);if (successor != null) {return successor.handWork(t);}return t;}/*** 自己的处理逻辑** @param intput* @return*/abstract T handWork(T intput);
}

对应的我们基于这个抽象类实现两个字符处理器,ProcessingStr1会将收到的中文逗号换位英文逗号:

public class ProcessingStr1 extends ProcessingObject<String> {@OverrideString handWork(String intput) {return intput.replace(",", ",");}
}

ProcessingStr2 会将中文句号替换为英文句号:

public class ProcessingStr2 extends ProcessingObject<String> {@OverrideString handWork(String intput) {return intput.replace("。", ".");}
}

测试代码和输出结果如下:

public static void main(String[] args) {ProcessingObject<String> p1 = new ProcessingStr1();ProcessingObject<String> p2 = new ProcessingStr2();p1.setSuccessor(p2);System.out.println(p1.handle("hello,world。"));}

可以看到所有的中文符号都被替换成英文符号了:

hello,world.

话不多说,不难看出上文这种传入String返回String的方法,我们完全可以使用UnaryOperator函数式接口,它的函数式签名为(T)->T,很明显将我们的String类代入是成立的:

在这里插入图片描述

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {static <T> UnaryOperator<T> identity() {return t -> t;}
}

于是我们的责任链的处理器就被简化为下面这样:

//逗号替换UnaryOperator<String> p1 = i -> i.replace(",", ",");//句号替换
UnaryOperator<String> p2 = i -> i.replace("。", ".");

为了让两个处理器构成逻辑链,我们直接使用函数复合方法andThen,确保p1执行玩调用p2:

Function<String, String> function = p1.andThen(p2);
System.out.println(function.apply("hello,world。"));//hello,world.

小结

对于逻辑比较简单且需要适配设计模式的功能,可以尝试找到合适的函数式接口,按照它的签名实现功能,避免没必要的模板配置工作。

以上便是笔者关于Java8中函数式设计模式的案例实践全部内容,希望对你有帮助。

我是 sharkchiliCSDN Java 领域博客专家开源项目—JavaGuide contributor,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述

参考

Java 8 in Action:https://book.douban.com/subject/25912747/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/399757.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构+二叉遍历算法的应用

一、问题描述 编写一个程序&#xff0c;先用二叉树表示一个简单算术表达式&#xff0c;树的每一个 结点包括一个运算符或运算数。在简单算术表达式中只包含、-、 *、/和一位正整数且格式正确(不包含括号)&#xff0c;并且要按照先乘除后 加减的原则构造二叉树。如图 7.35 所示…

聚合平台项目优化(门面模式,适配器模式,注册器模式)

前言&#xff1a; 这篇文章的思路就是抛出问题&#xff0c;再思考解决方案&#xff0c;最后利用设计模式解决问题 项目背景&#xff1a; 聚合搜索平台的主要功能就是一个有强大搜索能力的一个项目 用户输入一个词&#xff0c;同时可以搜索出用户&#xff0c;文章和图片这种…

AI绘画: ComfyUI奥运高光时刻海报工作流,工作流拆解~

前言 点关注不迷路&#xff01; 这两天&#xff0c;阿里云的PAI ArtLab的ComfyUI新增了一个奥运高光时刻海报的工作流&#xff0c;小编测试下来&#xff0c;效果真的不错。不愧是大厂出品&#xff0c;必属精品。那么这次小编就简单梳理一下这个工作流的的各个部分&#xff0c…

基于vue框架的CKD电子病历系统nfa2e(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;患者,医生,药品信息,电子病历,临时医嘱,长期医嘱,健康科普 开题报告内容 基于Vue框架的CKD电子病历系统 开题报告 一、选题背景 随着信息技术的飞速发展和医疗信息化的深入推进&#xff0c;电子病历系统&#xff08;Electronic Medic…

分布式文件系统FastDFS入门

文章目录 一.分布式文件系统简介&#xff1a;二.FastDFS简介三.FastDFS组成Tracker ServerStorage Serverclient上传流程下载流程文件ID 四.FastDFS配置1.tracker.conf2.stroage 配置文件3.client配置文件 五.FastDFS使用六.代码实现通过execl调用客户端程序进行上传下载使用AP…

如何使用 Puppeteer 和 Node.JS 进行 Web 抓取?

什么是 Headlesschrome&#xff1f; Headless&#xff1f;是的&#xff0c;这意味着这个浏览器没有图形用户界面 (GUI)。不用鼠标或触摸设备与视觉元素交互&#xff0c;你需要使用命令行界面 (CLI) 来执行自动化操作。 Headlesschrome 和 Puppeteer 很多网页抓取工具都可适用…

成功解决7版本的数据库导入 8版本数据库脚本报错问题

我 | 在这里 ⭐ 全栈开发攻城狮、全网10W粉丝、2022博客之星后端领域Top1、专家博主。 &#x1f393;擅长 指导毕设 | 论文指导 | 系统开发 | 毕业答辩 | 系统讲解等。已指导60位同学顺利毕业 ✈️个人公众号&#xff1a;热爱技术的小郑。回复 Java全套视频教程 或 前端全套视频…

访问网站显示不安全打不开怎么办如何处理

当访问网站时浏览器提示“不安全”&#xff0c;这通常是由于多种原因造成的。下面是一些常见的原因及其解决办法&#xff1a; 未启用HTTPS协议 如果网站仅使用HTTP协议&#xff0c;数据传输没有加密&#xff0c;会被浏览器标记为“不安全”。解决办法是启用HTTPS协议&#xff…

一篇文章教会你如何使用Haproxy,内含大量实战案例

1. Haproxy 介绍 HAProxy是法国开发者 威利塔罗&#xff08;Willy Tarreau&#xff09; 使用C语言编写的自由及开放源代码软件&#xff0c;是一款具备高并发&#xff08;万级以上&#xff09;、高性能的TCP和HTTP应用程序代理. HAProxy运行在当前的硬件上&#xff0c;可以支持…

5款在线伪原创改写软件,智能改写文章效果好

在这个信息爆炸的时代&#xff0c;内容创作变得愈发重要&#xff0c;而对于创作者来说&#xff0c;有时需要一些得力的伪原创改写工具来辅助我们更好地改写出高质量的内容。今天我要和大家分享5款令人惊喜的在线伪原创改写软件&#xff0c;它们以出色的智能改写效果&#xff0c…

【Kubernetes】身份认证与鉴权

一&#xff0c;认证 所有 Kubernetes 集群有两类用户&#xff1a;由Kubernetes管理的ServiceAccounts(服务账户)和(Users Accounts)普通账户。 两种账户的区别&#xff1a; 普通帐户是针对(人)用户的&#xff0c;服务账户针对Pod进程普通帐户是全局性。在集群所有namespaces…

【Ai学习】一个技巧,解决99%Comfyui报错!

前言 comfyui以极高灵活度及节点化工作流&#xff0c;深受AI绘画者追捧&#xff0c;每当新的模型开源&#xff0c;comfyui都是最先进行适配。 comfyui高度兼容性及灵活性带来丰富强大的扩展&#xff08;插件&#xff09;生态&#xff0c;同时也带来一系列插件安装的问题&…

从今年的计算机视觉比赛看风向

记第一次参加CV比赛的经历-长三角&#xff08;芜湖&#xff09;人工智能视觉算法大赛-CSDN博客 去年参赛的记录里说了&#xff1a; 最近&#xff0c;同样的由芜湖举办的比赛又上线了&#xff0c;果然&#xff1a; 2023年是这些赛题&#xff0c;典型的CV&#xff1a; 今年变成…

阴阳脚数码管

1.小故事 最近&#xff0c;我接到了一个既“清肺”又“烧脑”的新任务&#xff0c;设计一个低功耗蓝牙肺活量计。在这个项目中我们借鉴了一款蓝牙跳绳的硬件设计方案&#xff0c;特别是它的显示方案——数码管。 在电子工程领域&#xff0c;初学者往往从操作LED开始&#xff…

【网络】IP的路径选择——路由控制

目录 路由控制表 默认路由 主机路由 本地环回地址 路由控制表的聚合 网络分层 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 路由控制表 在数据通信中&#xff0c;IP地址作为网络层的标识&#xff0c;用于指定数据包的目标位置。然而&#xff0c;仅有IP地址并不足以确…

基于LPF改进的反电势观测器+锁相环PLL的永磁无感控制

导读:上期文章介绍的基于EMF+PLL的中高速永磁无感控制,其中决定转速和位置的估算精度的是反电势的获取精度。直接计算法很难保证反电势的估算精度,所以本期文章介绍一种基于LPF的改进型EMF观测器。 一、基于LPF改进的EMF观测器 传统的EMF观测器的表达式为: 注:这里重点强…

01_Electron 跨平台桌面应用开发介绍

Electron 跨平台桌面应用开发介绍 一、Electron 的介绍二、关于 NW.js 和 Electron 介绍三、搭建 Electron 的环境1、准备工作&#xff1a;2、安装 electron 环境3、查看 electron 的版本&#xff0c;electron -v 一、Electron 的介绍 Electron 是由 Github 开发的一个跨平台的…

Oracle事务是怎么练成的

什么是事务 事务是数据库管理系统执行过程的一个逻辑单位&#xff0c;由一系列有限的数据库操作序列构成&#xff0c;事务必须满足‌ACID属性。ACID理论是数据库中最重要的概念之一&#xff0c;分别代表原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consisten…

Django基础知识

文章目录 新建Django项目helloworld关联数据库admin 新建Django项目 创建django-admin startproject project_name 运行 python manage.py runserver 创建app: python manage.py startapp app_name 目录&#xff1a; 配置文件 settings.py 路由配置 urls.py 项目管理 manage.p…

极光流星大爆发

卑微仔广东持续200%含云量&#xff0c;线上观望大家分享的极光与流星共舞的神奇场景。 极光与流星相伴的瞬间&#xff0c;永远震撼于绝美的星空 开始放毒&#xff08;放图放图&#xff09;&#xff08;以下均拍摄于12日晚至13日晨这一时间段&#xff09;&#xff1a; 先驱猎光…