当前位置: 首页 > news >正文

Java8实战 - 行为参数化传递代码

背景:

根据《java8实战》把第二章简单概括一下。

在软件工程中,一个最重要的问题是,用户的需求会一直变化,如何应对不断变化的需求,并且把工作量降到最低是需要考虑的,而行为参数化就是一个处理频繁变更需求的软件开发模式。

在我看来,行为参数化,是拿出一块代码段,准备好却不去执行,这个代码块会被其他部分调用,意味着可以推迟这个代码的执行。

下面用在库存中筛选苹果的案例来说明。

第一版:筛选绿苹果

public static List<Apple> filterGreenApples(List<Apple> inventory) {List<Apple> result = new ArrayList<>();for(Apple app: inventory) {if("green".equals(apple.getColor())) {result.add(apple);}}return result;
}

上面的代码可以就是筛选绿色苹果,但是如果现在需求变了,需要筛选红色苹果,那么第一反应是在上面的函数入参中,加入颜色条件来匹配。

第二版:颜色作为参数

public static List<Apple> filterGreenApples(List<Apple> inventory, String color) {List<Apple> result = new ArrayList<>();for(Apple app: inventory) {if(apple.getColor().equals(color)) {result.add(apple);}}return result;
}
List<Apple> greenApples = filterAppleByColor(Inventory, "green");
List<Apple> greenApples = filterAppleByColor(Inventory, "red");

这样可以得到最终答案,但是又出现了一个问题,现在需求变成需要能区分轻苹果和重苹果.

于是把上面代码拷贝一份又写了个针对重量的

第三版:重量作为参数

public static List<Apple> filterGreenApples(List<Apple> inventory, int weight) {List<Apple> result = new ArrayList<>();for(Apple app: inventory) {if(apple.getWeight() > weight) {result.add(apple);}}return result;
}

这样虽然可以,但是打破了DRY(Don't Repeat Yourself, 不要重复自己)软件工程原则,当然不重复情况下,还可以加上一个标志位来判断是对哪个条件进行查询,如下

第四版:颜色和重量统一查询函数

public static List<Apple> filterGreenApples(List<Apple> inventory, String color,int weight, boolean flag) {List<Apple> result = new ArrayList<>();for(Apple app: inventory) {if((flag && apple.getColor().equals(color)) || (!flag && apple.getWeight() > weight)){result.add(apple);}}return result;
}

这样的代码可读性很差,并且标志位现在只是颜色和重量,如果再加查询条件,比如产地,形状等,就无法满足需求了.

行为参数化传递代码

考虑将选择的标准进行建模,比如绿色的吗,重量超过150克吗,来返回一个boolean值,这种返回boolean值函数称为”谓词“,定义一个接口来选择标准建模:

public interface ApplePredicate{boolean test(Apple apple);
}

那么就可以又很多实现类了,比如

public class AppleHeavyWeightPredicate implements ApplePredicate {public boolean test(Apple apple) {return apple.getWeight() > 150;}
}public class AppleGreenColorPredicate implements ApplePredicate {public boolean test(Apple apple) {return "green".equals(apple.getColor());}
}

把不同filter方法的不同行为封装起来,称为“策略”,然后再运行时选择一个算法,这个算法族就是applePredicate。

第五版:applePredicate改造后

public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p) {List<Apple> result = new ArrayList<>();for(Apple app: inventory) {if(p.test(apple)){result.add(apple);}}return result;
}

这样使用灵活多了,假设选择需求变了,组合条件,既要红苹果,又要重量超过150克,那么就再增加一个类实现ApplePredicate就行

public class AppleRedAndHeavyPredicate implements ApplePredicate {public boolean test(Apple apple) {return "red".equals(apple.getColor()) && apple.getWeight() > 150;}
}List<Apple> redAndHeavyApple = filterApples(inventory, new AppleRedAndHeavyPredicate());

 但是这样还不完美,因为现在filterApples入参都需要一个new一个过滤条件相关的对象,并且实现test方法,为了在进一步减少代码,还可以用匿名类和lambda表达式

第六版:匿名类

List<Apple> redAndHeavyApple = filterApples(inventory, new AppleRedAndHeavyPredicate() {public boolean test(Apple apple) {return "red".equals(apple.getColor());}
});

匿名类看起来减少了类的实现代码,但是调用时候还是塞了很多代码。那么就到了最后一个

第七版:Lambda表达式

List<Apple> redAndHeavyApple = filterApples(inventory, (Apple apple) -> "red".equals(apple.getColor()));

这样看起来就干净多了。现在filterApples只是作用于苹果的筛选,我们甚至更进一步,造一个通用filter,用泛型来替代Apple,如下:

public interface Predicate<T> {boolean test(T t);
}public static <T> List<T> filter<List<T> list, Predicate<T> p> {List<T> result = new ArrayList<>();for(T e: list){if(p.test(e)){result.add(e);}        }
}

这样就可以把filter方法用在香蕉,桔子,等等上。这边的Predicate<T>是一个函数式的接口,为了缩短篇幅,会在下个博客讲

相关文章:

Java8实战 - 行为参数化传递代码

背景&#xff1a; 根据《java8实战》把第二章简单概括一下。 在软件工程中&#xff0c;一个最重要的问题是&#xff0c;用户的需求会一直变化&#xff0c;如何应对不断变化的需求&#xff0c;并且把工作量降到最低是需要考虑的&#xff0c;而行为参数化就是一个处理频繁变更需…...

jmeter,取“临时重定向的登录接口”响应头中的cookie

1、线程组--创建线程组&#xff1b; 2、线程组--添加--取样器--HTTP请求&#xff1b; 3、Http请求--添加--后置处理器--正则表达式提取器&#xff1b; 4、线程组--添加--监听器--查看结果树&#xff1b; 5、线程组--添加--取样器--调试取样器。 首先理解 自动重定向 与跟随…...

流程控制之条件判断

目录 流程控制之条件判断 2.1.if语句语法 2.1.1单分支结构 2.1.2双分支结构 2.1.3多分支结构 2.2.案例 例一: 例2: 例3: 例4: 例5: 例6: 例7: 例8: 例9: 2.3.case多条件判断 2.3.1.格式 2.3.2.执行过程 例10: 流程控制之条件判断 2.1.if语句语法 2.1.1单分…...

2 - Electron 核心概念

Electron 核心概念 主进程 通过Node.js、Electron提供的API与系统底层打交道启动项目时运行的 main.js 脚本就是我们说的主进程。在主进程运行的脚本可以以创建 Web 页面的形式展示 GUI。主进程只有一个 渲染进程 每个 Electron 的页面都在运行着自己的进程&#xff0c;这样…...

Cmake找不到mysql.h和libmysqlclient.so

查看mysql.h和libmysqlclient.so的路径 eikeik-Virtual-Machine:~/桌面/dbpool/bin$ locate mysql.h /usr/include/mysql/mysql.h eikeik-Virtual-Machine:~/桌面/dbpool/bin$ locate libmysqlclient.so /usr/lib/x86_64-linux-gnu/libmysqlclient.so /usr/lib/x86_64-linux-g…...

图论——二分图

图论——二分图 二分图通俗解释 有一个图&#xff0c;将顶点分成两类&#xff0c;边只存在不同类顶点之间&#xff0c;同类顶点之间设有边。称图 G 为二部图&#xff0c;或称二分图&#xff0c;也称欧图。 性质 二分图不含有奇数环图中没有奇数环&#xff0c;一定可以转换为二…...

国产浪潮服务器:风扇免手动调节脚本

简介&#xff1a;浪潮集团&#xff0c;是中国本土顶尖的大型IT企业之一&#xff0c;中国领先的云计算、大数据服务商。浪潮集团旗下拥有浪潮信息、浪潮软件、浪潮国际&#xff0c;业务涵盖云计算、大数据、工业互联网等新一代信息技术产业领域&#xff0c;为全球120多个国家和地…...

智能科技企业网站搭建的作用是什么

随着科学技术快速提升&#xff0c;各种智能产品随之而来&#xff0c;每个赛道里都涌入了大量企业商家&#xff0c;有些热门产品更是广受关注&#xff0c;对企业来说&#xff0c;形象、品牌、信息等方面需要完美呈现到用户眼前&#xff0c;而网站无疑是很好的工具。 企业通过【…...

【多组学数据驱动的机器学习:生物医学研究的创新与突破】

简介&#xff1a;随着生物医学研究的不断发展&#xff0c;多组学数据在疾病预防、诊断和治疗方面发挥着越来越重要的作用。本文将介绍如何利用机器学习技术对多组学数据进行综合分析&#xff0c;以及这种方法在生物医学研究中的优势和潜力。 正文&#xff1a; 一、多组学数据…...

AI影响谷歌正在推出新的人工智能模型,用于医疗保健。以下是医生如何使用它们的介绍

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

云仓酒庄带您品法国葡萄酒

说起葡萄酒肯定绕不开法国&#xff0c;法国葡萄酒闻名中外&#xff0c;口碑卓越。作为世界上的产酒大国&#xff0c;可以说是每一寸土地都可以种植葡萄。云仓酒庄的品牌雷盛红酒分享这么优秀的一个葡萄酒产酒国有哪些特点呢&#xff1f; 1.产区特色&#xff1a;波国有最著名的…...

XIAO ESP32S3之实现口罩检测

一、例程介绍 此例程是运行FOMO 轻量检测模型实现人员佩戴口罩检测&#xff0c;Demo中已包含训练好的模型参数&#xff0c;无需再训练。 FOMO(Faster Objects, More Objects) 是由 Edgeimpulse 工程师提出的一种轻量级的目标检测模型&#xff0c;其主要特点是模型非常小&#…...

LVS简介及LVS-NAT负载均衡群集的搭建

目录 LVS群集简介 群集的含义和应用场景 性能扩展方式 群集的分类 负载均衡&#xff08;LB&#xff09; 高可用&#xff08;HA&#xff09; 高性能运算&#xff08;HPC&#xff09; LVS的三种工作模式 NAT 地址转换 TUN IP隧道 IP Tunnel DR 直接路由 Direct Rout…...

ElasticSearch之cat segments API

命令样例如下&#xff1a; curl -X GET "https://localhost:9200/_cat/segments?vtrue&pretty" --cacert $ES_HOME/config/certs/http_ca.crt -u "elastic:ohCxPHQBEs5*lo7F9"执行结果输出如下&#xff1a; index shard prirep ip segment g…...

docker镜像与容器的迁移

docker容器迁移有两组命令&#xff0c;分别是 save & load &#xff1a;操作的是images&#xff0c; 所以要先把容器commit成镜像export & import&#xff1a;直接操作容器 我们先主要看看他们的区别&#xff1a; 一 把容器打包为镜像再迁移到其他服务器 如把mysq…...

Cmake基础(2)

使用一个简单的示例来应用cmake&#xff0c;无任何三方库的单一的应用程序项目 你可以收获 使用cmake生成VS项目生成mingw项目(makefile) 1 首先新建一个cpp&#xff0c;我们要做一个控制台应用程序 #include<iostream> void main(){std::cout<<"hello cm…...

OSPF理论总结与实验

第1章 OSPF[1] 本章阐述了OSPF协议的特征、术语&#xff0c;OSPF的路由器类型、网络类型、区域类型、LSA类型&#xff0c;OSPF报文的具体内容及作用&#xff0c;描述了OSPF的邻居关系&#xff0c;通过实例让读者掌握OSPF在各种场景中的配置。 本章包含以下内容&#xff1a; …...

浅谈安科瑞无线测温产品在巴西某工厂的应用

摘 要&#xff1a;高压开关设备是变电站和配电站中保证电力系统安全运行的重要设备之一,因此,开关柜的稳定运行对于整个电力系统有非常重要的意义。设备老化、长期高负荷运行都可能使设备局部温度过高而发生火灾&#xff0c;因此,对变电站内的敏感设备进行温度检测变得尤为重要…...

RabbitMQ 命令

Docker # 进入容器 > docker exec -it rabbitmq /bin/bash# 帮助 > rabbitmq-service help# 查看所有队列 > rabbitmqctl list_queues Windows 进入安装目录【D:\Program Files\RabbitMQ Server\rabbitmq_server-3.9.10\sbin】输入cmd # 帮助 > rabbitmq-servic…...

数据库系列之简要对比下GaussDB和OpenGauss数据库

GaussDB作为一款企业级的数据库产品&#xff0c;和开源数据库OpenGauss之间又是什么样的关系&#xff0c;刚开始接触的时候是一头雾水&#xff0c;因此本文简要对比下二者的区别&#xff0c;以加深了解。 1、GaussDB和OpenGauss数据库简要对比 GaussDB是华为基于PostgreSQL数据…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...