Java8实战——通过行为参数化传递代码 顶
1、初试牛刀:筛选绿苹果
第一个解决方案可能是下面这样的:
public static List<Apple> filterGreenApples(List<Apple> inventory){
List<Apple> result=new ArrayList<>();
//仅仅筛选出绿苹果
for (Apple apple : inventory) {
if ("green".equals(apple.getColor())){
result.add(apple);
}
}
return result;
}
上面代码只针对绿苹果进行筛选,现在,我还想筛选出红苹果,该怎么做呢?简单的解决办法就是重复写一个方法,再改条件为红苹果,但是,要筛选的颜色有多种的情况,这样写会导致代码十分冗余,所以我们第一步尝试将其抽象化。
2、再展身手:把颜色作为参数
public static List<Apple> filterGreenApples(List<Apple> inventory,String color){
List<Apple> result=new ArrayList<>();
//颜色作为参数
for (Apple apple : inventory) {
if (color.equals(apple.getColor())){
result.add(apple);
}
}
return result;
}
但是现在又想根据苹果的重量对苹果进行筛选,那是不是也要用另外一个参数表示苹果重量呢?之后我又想加个标志区分对颜色和重量的查询呢?下面是展示一般写法,但是很傻。
3、第三次尝试:对你能想到的每个属性做筛选
public static List<Apple> filterGreenApples(List<Apple> inventory,String color,int weight,boolean flag){
List<Apple> result=new ArrayList<>();
for (Apple apple : inventory) {
if (flag && color.equals(apple.getColor())|| (!flag && apple.getWeight()>weight)){
result.add(apple);
}
}
return result;
}
4、柳暗花明:行为参数化
我们可以把行为进行参数化,来达到更高层次的抽象,首先定义一个统一的标准接口,再通过不同子类对其进行实现,这有点类似于策略设计模式的赶脚。
//封装了对选择苹果的策略
public interface ApplePredicate {
//具体算法交给子类去实现
boolean test (Apple apple);
}
//颜色算法
public class AppleGreenColorPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return "green".equals(apple.getColor());
}
}
//重量算法
public class AppleHeavyWeightPredicate implements ApplePredicate {
@Override
public boolean test(Apple apple) {
return apple.getWeight()>150;
}
}
5、第四次尝试:根据抽象条件筛选
public static List<Apple> filterApples(List<Apple> inventory,ApplePredicate p){
List<Apple> result = new ArrayList<>();
//行为参数化
for (Apple apple : inventory) {
if (p.test(apple)){
result.add(apple);
}
}
return result;
}
我们在使用的时候可以传递不同的策略实现来达到目的
List<Apple> heavyApples = filterApples(inventory, new AppleHeavyWeightPredicate());
List<Apple> greenApples = filterApples(inventory, new AppleGreenColorPredicate());
但是这样有个问题,就是每个策略我都要定义一个实现类去实现某个算法,导致后面如果有很多策略,会增加很多的类,我们知道使用匿名类也是一种不错的选择
6、第五次尝试:使用匿名类
List<Apple> redApples = filterApples(inventory, new ApplePredicate() {
@Override
public boolean test(Apple apple){
return "red".equals(apple.getColor());
}
});
但是问题又来了,匿名类还是不够好,第一,它往往很笨重,占用了很多的空间,第二,使用起来让人费解,导致代码可读性不高,即使匿名类处理在某种程度上改善了为一个接口声明好几个实体类的啰嗦问题,但是还是不能令人满意,自java8引入的lambda表达式——一种更简洁的传递代码的方式解决了这个问题。下面我们利用lambda表达式来改写前面的代码吧
7、第六次尝试:使用Lambda表达式
List<Apple>result= filterApples(inventory, (Apple apple)-> "red".equals(apple.getColor()));
不得不承认,使用lambda表达式改写之前的代码确实干净很多,因为它看起来更像问题陈诉本身了,解决了啰嗦的问题
8、第七次尝试:将List类型抽象化
在通往抽象的路上,我们还可以进一步。目前filterApples方法还只适用Apple,我们还可以尝试适用在其他水果上。
public interface Predicate<T> {
boolean test(T 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);
}
}
return result;
}
现在你可以吧filter方法作用在橘子,香蕉等列表上了。
9、小结
行为参数化,就是一个方法接收不同的行为作为参数,并在内部使用他们,完成不同行为的能力。 行为参数化可以让代码更好的适应不断变化的要求,减轻未来的工作量。 传递代码,就是将新行为作为参数传递给方法,但是在java8之前实现起来很啰嗦。为接口声明许多只用一次的实体类而造成的啰嗦代码,在java8之前可以用匿名类来减少。 java API 包含很多可以用不同行为进行参数化的方法,包括排序、线程等。
- 包学会之浅入浅出Vue.js:结业篇
- 迈克尔•戴尔:人工智能杀手?技术反乌托邦?不存在的
- 你知道吗?多个类多线程环境下静态构造函数的执行顺序
- 云端架构师养成之三:微信也在用的消息队列服务
- 现在 tensorflow和mxnet 很火,是否还有必要学习 scikit-learn 等框架?
- ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上
- 改进版CodeTimer及XCode性能测试
- 常见测试术语解析
- 秦俊:开放 DevOps 敏捷开发套件,助力开发者驰骋云端
- 开源组件NanUI一周年-使用HTML/CSS/JS来构建.Net Winform应用程序界面
- 邱寒:新零售笔记(四)基于区块链大数据的人工智能
- 腾讯云GAME-TECH沙龙干货回顾:网龙《英魂之刃口袋版》开发经验分享
- ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则
- 【深度学习系列】用PaddlePaddle和Tensorflow实现经典CNN网络AlexNet
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 3分钟短文 | Laravel复杂SQL超多WHERE子句,本地作用域你没用过
- 3分钟短文 | Laravel同时连接多个数据库,你用啥办法?
- 3分钟短文 | PHP 连接2个字符串的8个方法,新手常犯错
- nodejs源码分析之connect
- 你应该了解的Nacos配置中心
- Jenkins CLI 命令行 v0.0.30
- 2020新鲜出炉的“面筋”,够刁钻
- Spring注解配置应该怎么玩
- 算法篇:链表之倒数第k个节点
- 彻底搞懂 Java 线程池,干啥都不再发憷
- Android Camera1中的对焦与测光
- 使用R语言获得16S物种丰度
- 二叉树的基础---四种遍历方式的 Java 实现
- MySQL 架构与历史
- 通过案例学Python之assert