【函数式接口使用✈️✈️】通过具体的例子实现函数结合策略模式的使用

ops/2024/11/15 8:35:08/

目录

🍸前言

🍻一、核心函数式接口

1. Consumer

2.  Supplier

3.  Function,>

🍺二、场景模拟

         1.面向对象设计

2. 策略接口实现(以 Function 接口作为策略) 

🍹三、对比

🍷文末


🍸前言

        在 Java 8 中引入了Stream API 新特性,这使得函数式编程风格进一步得到巩固,其中伴随着Lambda 表达式和 Stream API 的广泛使用,另一种函数式接口风格亦可以简化代码提升可读性和拓展性,具体如下

🍻一、核心函数式接口

1. Consumer<T>

  • 定义了一个接受单一输入参数并且无返回值的操作。常用于数据处理流程中的消费型操作,如打印日志、更新数据库等。
  •         List<String> names = Arrays.asList("Alice", "Bob", "Charlie");names.forEach(e-> System.out.println("Welcome login : "+e));// 这里是使用的Consumer<String>,给一个参数执行相关操作// 或者定义一个自定义ConsumerConsumer<String> logAction = name -> System.out.println("Logging action for: " + name);names.forEach(logAction);

2.  Supplier<T>

  • 定义了一个不接受任何参数但是会产生一个结果的方法引用。常用于提供数据来源或计算某个值。
  •         Supplier<Integer> randomIntSupplier = () -> ThreadLocalRandom.current().nextInt(1, 100);System.out.println(randomIntSupplier.get()); // 输出一个1到100之间的随机整数

3.  Function<T, R>

  • 定义了一个接受一个输入参数并产生一个输出结果的方法引用。常用于数据转换、映射或计算。
  •         List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);List<Double> doubles = numbers.stream().map((Function<Integer, Double>)                                 Integer::doubleValue).collect(Collectors.toList());doubles.forEach(System.out::println);// 或者自定义FunctionFunction<String, String> upperCaseTransformer = String::toUpperCase;String transformed = upperCaseTransformer.apply("hello"); // 输出 "HELLO"System.out.println(transformed);

🍺二、场景模拟

         1.面向对象设计

        比如常见的促销活动中,不同的促销策略计算出商品的最终价格是不一样的,采用传统的面向对象设计的话,需要为每一个促销活动创建独立的方法或者类了,并在购物车类中通过直接调用相应的方法计算,如下:

public class ShoppingCart {//购物车中的商品列表private List<Product> products;//普通不打折,统计所有商品的价格即可public double calculateTotalPriceWithNormalPrice() {double totalPrice = products.stream().map(Product::getPrice).reduce(0.0, Double::sum);return totalPrice;}//促销打九折,统计商品价格的九折public double calculateTotalPriceWithTenPercentDiscount() {double totalPrice = products.stream().map(product -> product.getPrice() * 0.9).reduce(0.0, Double::sum);return totalPrice;}//促销直减50 ,小于0 的按照0元计算public double calculateTotalPriceWithFiftyDollarsOff() {double totalPrice = products.stream().map(product -> Math.max(product.getPrice() - 50.0, 0.0)).reduce(0.0, Double::sum);return totalPrice;}// 调用示例public void processCheckout(CheckoutType type) {switch (type) {case NORMAL_PRICE:double normalPrice = calculateTotalPriceWithNormalPrice();// 处理正常价格结算逻辑break;case TEN_PERCENT_DISCOUNT:double tenPercentDiscount = calculateTotalPriceWithTenPercentDiscount();// 处理九折结算逻辑break;case FIFTY_DOLLARS_OFF:double fiftyDollarsOff = calculateTotalPriceWithFiftyDollarsOff();// 处理直减50美元结算逻辑break;}}// 其他方法...
}enum CheckoutType {NORMAL_PRICE,TEN_PERCENT_DISCOUNT,FIFTY_DOLLARS_OFF
}

        这种方式增加了代码的耦合度,并且如果需要新增或者修改促销策略,就需要修改ShoppingCart类

2. 策略接口实现(以 Function 接口作为策略) 

import java.util.function.Function;public interface PromotionStrategy extends Function<Double, Double> {// 不需要额外的方法,因为Function本身就是一种策略(接受一个参数,返回一个结果),它接受原始价格并返回打折后的价格
}

        创建几个具体的策略实现

public class NormalPriceStrategy implements PromotionStrategy {@Overridepublic Double apply(Double originalPrice) {return originalPrice; // 正常价格,不做打折处理}
}public class TenPercentDiscountStrategy implements PromotionStrategy {@Overridepublic Double apply(Double originalPrice) {return originalPrice * 0.9; // 打九折}
}public class FiftyDollarsOffStrategy implements PromotionStrategy {@Overridepublic Double apply(Double originalPrice) {return Math.max(originalPrice - 50.0, 0.0); // 直减50美元,价格不能低于0}
}

            之后,在购物车计算逻辑中,可以根据用户选择的促销策略动态计算商品的价格:

public class ShoppingCart {private List<Product> products;private PromotionStrategy promotionStrategy;public ShoppingCart(PromotionStrategy strategy) {this.promotionStrategy = strategy;// 初始化产品列表...}public double calculateTotalPrice() {double totalPrice = products.stream().map(Product::getPrice).map(promotionStrategy).reduce(0.0, Double::sum);return totalPrice;}// 其他方法...
}// 使用示例:
ShoppingCart cart = new ShoppingCart(new TenPercentDiscountStrategy());
// 添加商品到cart...
double finalPrice = cart.calculateTotalPrice(); // 根据策略计算总价

        这个例子就是使用 PromotionStrategy 扮演了策略角色,不同的折扣策略通过实现 Function<Double,Double> 接口来决定如何计算折扣价,在使用时,可以根据需要选择并注入不同的策略实现。

🍹三、对比

策略模式面向对象设计
优点
  • 开放封闭原则策略模式鼓励对扩展开放,对修改封闭。当需要增加新的促销策略时,只需要增加一个新的策略类,不需要修改现有的购物车类或者其他已有代码。
  • 代码复用:每个策略类(如NormalPriceStrategyTenPercentDiscountStrategyFiftyDollarsOffStrategy)可以独立于购物车类使用,增强了代码的复用性。
  • 低耦合:购物车类与具体的促销策略解耦,使得系统更灵活,更容易维护。
  • 对于简单的场景,直接在购物车类中添加多个计算方法直观易懂,初学者更容易接受。
缺点
  • 策略种类增多时,可能会导致策略接口的家族变得庞大,若策略逻辑差异不大,可能会造成代码冗余。
  • 耦合度高:购物车类与具体的促销逻辑紧密耦合,当促销策略发生变化时,必须修改购物车类的代码。
  • 扩展困难:若促销策略种类增加,会导致购物车类的代码臃肿,且不利于代码维护。
  • 代码复用性差:对于每一种新的促销活动,都需要在购物车类中添加新的方法,无法直接复用现有逻辑。

        其实不难看出,在面对频繁变化的业务逻辑(如促销策略)时,策略模式的优势明显,它有助于代码的可维护性、扩展性和复用性。而在简单、固定的场景下,直接在购物车类中硬编码计算逻辑可能显得更为直接简单。然而,考虑到长期的软件迭代和维护成本,推荐采用策略模式来优化代码结构。

🍷文末

        文章到这里就结束了~


http://www.ppmy.cn/ops/8498.html

相关文章

常见的SQL优化策略

1、选择性地选择列&#xff1a; 避免使用SELECT *&#xff0c;只选择需要的列。 2、使用索引&#xff1a; 1、确保查询中用于过滤、排序和连接的列都有索引。 2、索引会增加写操作的开销&#xff0c;所以要根据实际情况权衡。 3、使用复合索引时&#xff0c;要注意列的顺序&…

宝塔面板国际版aaPanel 精简版安装

宝塔面板国际版aaPanel 精简版安装 很多人都知道宝塔面板&#xff0c;但不知道宝塔面板还有英文版&#xff0c;宝塔面板英文版不是单纯的宝塔面板的翻译&#xff0c;而是根据老外的使用习惯及国外的网络环境做了一定的优化&#xff0c; 比如&#xff1a;去掉了手机号验证、去…

java学习笔记3

5. 多重循环和程序调试 5.1 多重循环 多重循环是指循环中嵌套循环结构 多重循环注意事项 各种循环可以互相嵌套一般不要超过三层嵌套外层循环变化一次,内层循环要全部执行完代码 **需求1:**使用循环嵌套输出10*10的矩形 public static void demo() {for (int i = 0; i <…

请编写一个函数void fun(int m,int k,int xx[]),该函数的功能是:将大于整数m且紧靠m的k个素数存入xx所指的数组中。

本文收录于专栏:算法之翼 https://blog.csdn.net/weixin_52908342/category_10943144.html 订阅后本专栏全部文章可见。 本文含有题目的题干、解题思路、解题思路、解题代码、代码解析。本文分别包含C语言、C++、Java、Python四种语言的解法和详细的解析。 题干 请编写一个函…

实用VBA:19.Excel一键修复文件链接

1.需求场景 此前与大家分享过一键提取文件目录和文件名的方法&#xff0c;并且VBA中加一句语句就可以使提取出来的文件名带有链接&#xff0c;这样很方便在对大量文件进行检查时不必在资源管理器里到处翻目录&#xff0c;所见即所得&#xff0c;点击文件名即可打开文件。是个实…

Linux 存储:NAND 写入异常案例 (1)

文章目录 1. 前言2. 案例背景3. 案例问题4. 案例分析4.1 普通文件写入流程概要4.2 dd 写 NAND 时&#xff0c;会不会使用 page cache &#xff1f;4.3 dd 写 NAND 时&#xff0c;对比 U-Boot 读 NAND&#xff0c;是否采用了相同的坏块策略 &#xff1f;4.3.1 U-Boot 读 NAND 过…

[Java EE] 计算机工作原理与操作系统简明概要

1. 计算机工作原理 1.1 生活中常见的计算机 计算机分为通用计算机和专用计算机,计算机并不单单指的是电脑,还有我们平时使用的手机,ipad,智能手表等终端设备都是计算机.还有我们用户不常见的计算机,比如服务器. 还有许多嵌入式设备(针对特定场景定制的"专用计算机"…

Amazon MemoryDB for Redis的探索和实践

一、背景 由于当下项目的日益增长的数据量&#xff0c;单机Redis已经远远不能满足我们的要求。考虑转成集群&#xff0c;但是直接在服务器中搭建Redis集群的话&#xff0c;EC2挂掉则Redis也会随之挂掉&#xff0c;耦合性太强。所以将Redis相关的服务全部抽取在单独的服务器上或…