2.行为参数的演变过程

news2024/12/24 8:14:03

2.行为参数的演变过程

行为参数化是软件开发模式,可以处理频繁变更的需求。它让你把一个代码块准备好但不执行,以后可以被其他部分调用,也可以作为参数传递给另一个方法,推迟执行。这样,方法的行为就基于参数化的代码块。

2.1 应对不断变化的需求

例如:现在需要一个方法直接可以找出绿色的水果。

//获取绿色的水果
public List<Fruit> filterGreenFruit(List<Fruit> fruits) {
    List<Fruit> greenFruits = new ArrayList<>();
    for (Fruit fruit : fruits) {
        if ("green".equals(fruit.getColor())) {
            greenFruits.add(fruit);
        }
    }
    return greenFruits;
}

方法直接显示的展示筛选水果的颜色,若是想要筛选其他颜色,将其相同的行为抽象化。

第二个解决方案:把颜色作为参数

    public List<Fruit> filterGreenFruit(List<Fruit> fruits,String color) {
        List<Fruit> greenFruits = new ArrayList<>();
        for (Fruit fruit : fruits) {
            if (color.equals(fruit.getColor())) {
                greenFruits.add(fruit);
            }
        }
        return greenFruits;
    }

把颜色作为参数,这样可以灵活应对不同颜色的筛选。

这时若是想要筛选水果的轻重,需要怎么处理呢?如下

    public List<Fruit> filterWeightFruit(List<Fruit> fruits,int weight) {
        List<Fruit> greenFruits = new ArrayList<>();
        for (Fruit fruit : fruits) {
            if (fruit.getWeight()>weight) {
                greenFruits.add(fruit);
            }
        }
        return greenFruits;
    }

解决方法看似没什么问题,但是复制了大部分的代码来实现对重量的筛选,因为这打破了DRY(Don’t Repeat Yourself,不要重复自己)的软件工程原则。如果你想要改变筛选遍历方式来提升性能呢?那就得修改所有方法的实现,而不是只改一个。从工程工作量的角度来看,这代价太大了。

需要把颜色和重量放到一个方法里,并且添加一个标识,如第三个解决方案

第三个解决方案:对想到的每个属性做筛选

    public List<Fruit> filterFruit(List<Fruit> fruits,int weight,String color,boolean flag) {
        List<Fruit> greenFruits = new ArrayList<>();
        for (Fruit fruit : fruits) {
            //颜色和重量同时满足
            if((!flag&&fruit.getColor().equals(color))||(flag&&fruit.getWeight()>weight)) {
                greenFruits.add(fruit);
            }
        }
        return greenFruits;
    }

这个解决方案挺糟糕的,从使用端无法看出flag的 true和false 是什么意思,若是想要绿色的大的水果将无法实现。下面将用行为参数化灵活实现此功能。

2.2 行为参数化

​ 前面我们添加多个参数来解决不断变化的需求,可以更高层次的抽象一个方法。一种可能的解决方案是对你的选择标准建模:你需要什么属性就根据某些属性实现test方法。代码如下

public interface ApplePredicate {
    boolean test(Fruit fruit);
}

现在你就可以用ApplePredicate的多个实现代表不同的选择标准了,比如

//选择重的水果
public class FruitHeavyWeightPredicate implements ApplePredicate{
    public boolean test(Apple apple){
    	return apple.getweight()>150;
    }
}
//选择绿色的水果
public class FruitHeavyColorPredicate implements ApplePredicate{
    public boolean test(Apple apple){
    	return apple.getColor.equals("green");
    }
}

有了上面的两种实现,filterApples方法更加简单易懂,那就是把ApplePredicate 对象当作filterFruit的一个参数,需要不同行为时,传递不同的实现对象,这就是行为参数化:让方法接受多种行为(或战略)作为参数,并在内部使用,来完成不同的行为。

第四次尝试:根据抽象条件筛选

 public List<Fruit> filterFruit(List<Fruit> fruits,ApplePredicate ap) {
        List<Fruit> greenFruits = new ArrayList<>();
        for (Fruit fruit : fruits) {
            //直接用接口中的方法
            if (ap.test(fruit)) {
                greenFruits.add(fruit);
            }
        }
        return greenFruits;
 }

1.传递代码/行为 --实际也是Java的接口:实际就是行为抽象。

​ 这段代码比之前尝试的时候灵活多了,读起来、用起来也更容易!现在你可以创建不同的ApplePredicate对象,并将它们传递给filterApples方法。例如 找出大于150g的红色水果,代码如下:

public class RedAndHeavyPredicate implements ApplePredicate {
    @Override
    public boolean test(Fruit fruit)
    {
        return "red".equals(fruit.getColor()) && fruit.getWeight() > 150;
    }

}

 List<Fruit> fruits = new ArrayList<>();
 ...省略添加数据步骤
 List<Fruit> fruitList = filterFruit(fruits, new RedAndHeavyPredicate());

2.多种行为,一个参数

行为参数化的好处在于你可以把迭代要筛选的集合的逻辑与对集合中每个元素应用的行为区分开来。这样你可以重复使用同一个方法,给它不同的行为来达到不同的目的。

3 对付啰嗦

人们都不愿意用那些很麻烦的功能或概念。目前,当要把新的行为传递给filterApples方法的时候,你不得不声明好几个实现ApplePredicate接口的类,然后实例化好几个只会提到一次的ApplePredicate对象。可以尝试下匿名类:匿名类和Java内部类差不多,但匿名类没有类名称。它允许声明并实例化一个类(随用随创建)。

第五次尝试:匿名类

    class RedPredicate implements ApplePredicate{
        @Override
        public boolean test(Fruit fruit)
        {
            return "red".equals(fruit.getColor()) && fruit.getWeight() > 150;
        }
    }
    //调用
    List<Fruit> redApples = filterFruit(fruits, new RedPredicate(){
            public boolean test(Fruit fruit) {
                return "red".equals(fruit.getColor());
            }
    });

第六次尝试:使用 Lambda 表达式

第五次尝试的代码在Java8可以写成如下代码:

List<Fruit> redFruit = filterFruit(fruits,(Fruit fruit)->"red".equals(fruit.getColor()))

在这里插入图片描述

2.3 例子

​ Java API中的很多方法都可以用不同的行为来参数化。这些方法往往与匿名类一起使用。

2.3.1用 Comparator 来排序

​ 对集合进行排序是一个常见的编程任务。比如相对库存中的苹果做排序,在Java 8中,List自带了一个sort方法(你也可以使用Collections.sort)。sort的行为可以用java.util.Comparator对象来参数化,它的接口如下:

// java.util.Comparator public interface Comparator
 {  public int compare(T o1, T o2); } 

可以随时创建Comparator的实现,用sort方法表现出不同的行为。如下

inventory.sort(
 new Comparator() {  
    public int compare(Apple a1, Apple a2){
      return a1.getWeight().compareTo(a2.getWeight()); 
    } 
   }
 ); 

java 8 的lambda表达式的写法如下

inventory.sort(  (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
2.3.2用 Runnable 执行代码块

线程就像是轻量级的进程:它们自己执行一个代码块。在Java里,你可以使用Runnable接口表示一个要执行的代码块。

// java.lang.Runnable
 public interface Runnable{ 
  public void run(); 
  }
  //使用内部类创建不同行为的线程
  Thread t = new Thread(
      new Runnable() {
           public void run(){ 
            System.out.println("Hello world");  
            } 
        }
   ); 
   //Java 8写法
   Thread t = new Thread(() -> System.out.println("Hello world"));
总结
  • 行为参数化,就是一个方法接受多个不同的行为作为参数,并在内部使用它们,完成不同行为的能力。

  • 行为参数化可让代码更好地适应不断变化的要求,减轻未来的工作量。

  • 传递代码,就是将新行为作为参数传递给方法。但在Java 8之前这实现起来很啰嗦。为接口声明许多只用一次的实体类而造成的啰嗦代码,在Java 8之前可以用匿名类来减少。

  • Java API包含很多可以用不同行为进行参数化的方法,包括排序、线程和GUI处理。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文深度剖析 ColBERT

近年来&#xff0c;向量搜索领域经历了爆炸性增长&#xff0c;尤其是在大型语言模型&#xff08;LLMs&#xff09;问世后。学术界开始重点关注如何通过扩展训练数据、采用先进的训练方法和新的架构等方法来增强 embedding 向量模型。 在之前的文章中&#xff0c;我们已经深入探…

领券拿外卖返利红包,最低0元吃外卖

小蚕荟是利用本地资源和自媒体优势构建的“本地生活服务”平台&#xff0c;总部位于杭州&#xff0c;旨在为用户提供热门的吃喝玩乐本地生活服务类产品。布局已覆盖杭州、南京、上海等一二线城市。 小蚕荟是一款专为用户吃外卖省钱的生活工具&#xff0c;单单可返利15元起&…

使用霍尔效应传感或磁场传感技术的应用

随着支持技术的增强&#xff0c;使用霍尔效应传感或磁场传感技术的应用目前已变得有效。本技术文档介绍了霍尔效应技术&#xff0c;并对应用进行了回顾&#xff0c;特别是区分霍尔传感器 IC 的主要类型以及它们可以支持的各种传感行为。此外&#xff0c;它还探讨了一些使能技术…

用智能插件(Fitten Code: Faster and Better AI Assistant)修改好了可以持久保存的vue3留言板

天际 第一修改是选项式&#xff1a; <!-- 模板结构 --> <template><div><textarea placeholder"请输入备注内容" v-model"newItem"></textarea><button click"addItem">添加</button><hr><…

HAL库点LED灯

文章目录 一、创建CubeMX项目操作步骤1.STM32CubeMX创建工程2.选择芯片3.Pinout & Configuration配置4.Clock Configuration配置5.Project Manager配置 二、实验&#xff08;一&#xff09;LED流水灯1.Keil修改代码2.实验现象3.keil波形仿真 &#xff08;二&#xff09;2只…

JVM学习-堆空间(一)

堆空间 每个进程&#xff08;JVM实例&#xff09;拥有唯一的方法区和堆空间&#xff0c;拥有唯一的Runtime实例(基于饿汉式方式)&#xff0c;线程共享进程的方法区和堆空间&#xff0c;每个线程拥有独立的程序计数器、本地方法栈和虚拟机栈。 一个JVM实例只存在一个堆内存&am…

MySQL主从复制(三):主从延迟

主备流程图&#xff1a; 谈到主备的复制能力&#xff0c;要关注的是上图中的两个黑色箭头。 一个箭头代表了客户端写入主库&#xff0c;另一个箭头代表的是sql_thread执行中转日志&#xff08;relay log&#xff09;。如果用箭头的粗细来代表并行度的话&#xff0c;那么真实情…

spring-boot集成slf4j(二)logback配置详解

一、configuration 根节点&#xff1a;configuration&#xff0c;作为顶级标签&#xff0c; 可以用来配置一些lockback的全局属性&#xff0c;常见的属性如下&#xff1a; &#xff08;1&#xff09;scan“true” &#xff1a;scan是否开启自动扫描&#xff0c;监控配置文件更…

【Crypto】看我回旋踢

文章目录 一、看我回旋踢二、知识点什么是ROT13&#xff1f;工作原理分析字符串格式 解题感悟 一、看我回旋踢 关键词回旋&#xff0c;盲猜ROT13 因为以 synt{ 开头&#xff0c;并以 } 结束&#xff0c;基本可以判断是ROT13 小小flag&#xff0c;拿下&#xff01; 二、知识点 …

Algoriddim djay Pro Ai for Mac:AI引领,混音新篇章

当AI遇上音乐&#xff0c;会碰撞出怎样的火花&#xff1f;Algoriddim djay Pro Ai for Mac给出了答案。这款专业的DJ混音软件&#xff0c;以AI为引擎&#xff0c;引领我们进入混音的新篇章。 djay Pro Ai for Mac的智能混音功能&#xff0c;让每一位DJ都能感受到前所未有的创作…

LAMDA面试准备(2024-05-23)

有没有学习过机器学习&#xff0c;提问了 FP-Growth 相比 Apriori 的优点 1. 更高的效率和更少的计算量&#xff08;时间&#xff09; FP-Growth 通过构建和遍历 FP-树 (Frequent Pattern Tree) 来挖掘频繁项集&#xff0c;而不需要像 Apriori 那样生成和测试大量的候选项集。具…

GQL 来了!ISO/IEC 正式发布 GQL 数据库国际标准!

历时四年筹备&#xff0c;超过20个国家的标准和技术专家参与制定&#xff0c;ISO/IEC GQL &#xff08;图查询语言&#xff09;标准于2024年4月12日正式发布&#xff01; 作为国际标准化组织&#xff08;ISO&#xff09;继 1987年 发布SQL后&#xff0c;唯一发布的数据库查询语…

数据库迁移——kettle开发01

背景&#xff1a;数据库的多种多样&#xff0c;在搭建项目之初&#xff0c;并没有详细考虑到数据库的建设&#xff0c;当增加配置不能满足业务场景需要时&#xff0c;这时候考虑到使用更高性能的数据库&#xff0c;如将MySQL更换为oracle数据库。或者在搭建新项目时&#xff0c…

【EXCEL_VBA_基础知识】08 在VBA中使用公式 ※

课程来源&#xff1a;王佩丰老师的《王佩丰学VBA视频教程》&#xff0c;如有侵权&#xff0c;请联系删除&#xff01; 目录 1. 函数在哪找&#xff1f; 1.1 工作表函数&#xff08;Application.WorksheetFunction.func&#xff09; 1.2 VBA函数 2. 常用VBA变量 3. 函数应用…

如何做好云安全防护

随着云计算技术的迅猛发展和普及&#xff0c;越来越多的企业和个人选择将数据和业务应用迁移到云平台&#xff0c;以享受其带来的高效、便捷和可扩展性。然而&#xff0c;云环境的复杂性和开放性也带来了前所未有的安全挑战。如何确保云环境中的数据安全&#xff0c;成为了每一…

瑞米派Ubuntu系统移植指南-米尔RemiPi

1.概述 Linux系统平台上有许多开源的系统构建框架&#xff0c;这些框架方便了开发者进行嵌入式系统的构建和定制化开发&#xff0c;目前比较常见的有Buildroot, Yocto, OpenEmbedded等等。 同时更多的传统的桌面系统也加入到嵌入式环境体系中&#xff0c;如Ubuntu&#xff0c…

微信小程序使用input标签遇到的问题

场景1&#xff1a;多个input标签切换无法聚焦问题 解决方案1&#xff1a; 在网上搜的用官方给的always-embed属性&#xff0c;但是也明确标注了只有ios可用 解决方案2&#xff1a; 使用focus属性&#xff1a;每次点击input标签都重新设置 wxml: <input adjust-position…

一文带你了解所有常用排序算法

目录 快速排序 堆排序 桶排序 归并排序 拓扑排序 本文主要介绍那些我在刷题过程中常用到的排序算法: 快速排序,堆排序,桶排序,归并排序,拓扑排序 其余算法例如冒泡,插入这种效率特别低的算法就不介绍了,用的可能性极小 每一个算法都将采用例题加解释的方式进行介绍 快速…

文心智能体应用示例:职场反PUA专家的诞生

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

LangChain llamaindex

LangChain 参考&#xff1a; 全流程 | Windows 系统本地部署开源模型阿里通义千问 QWEN 1.5&#xff0c;结合 LangChain-Chatchat 框架和向量数据库 FAISS、Milvus - 知乎