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

目录

前言

一、核心函数式接口

[1. Consumer](#1. Consumer)

[2. Supplier](#2. Supplier)

[3. Function,>](#3. Function,>)

二、场景模拟

1.面向对象设计

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

三、对比


前言

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

一、核心函数式接口

1.Consumer<T>

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

        // 或者定义一个自定义Consumer
        Consumer<String> logAction = name -> System.out.println("Logging action for: " + name);
        names.forEach(logAction);

2. Supplier<T>

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

3. Function<T, R>

  • 定义了一个接受一个输入参数并产生一个输出结果的方法引用。常用于数据转换、映射或计算。
java 复制代码
        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);

        // 或者自定义Function
        Function<String, String> upperCaseTransformer = String::toUpperCase;
        String transformed = upperCaseTransformer.apply("hello"); // 输出 "HELLO"
        System.out.println(transformed);

二、场景模拟

1.面向对象设计

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

java 复制代码
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 接口作为策略)

java 复制代码
import java.util.function.Function;

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

创建几个具体的策略实现

java 复制代码
public class NormalPriceStrategy implements PromotionStrategy {
    @Override
    public Double apply(Double originalPrice) {
        return originalPrice; // 正常价格,不做打折处理
    }
}

public class TenPercentDiscountStrategy implements PromotionStrategy {
    @Override
    public Double apply(Double originalPrice) {
        return originalPrice * 0.9; // 打九折
    }
}

public class FiftyDollarsOffStrategy implements PromotionStrategy {
    @Override
    public Double apply(Double originalPrice) {
        return Math.max(originalPrice - 50.0, 0.0); // 直减50美元,价格不能低于0
    }
}

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

java 复制代码
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)可以独立于购物车类使用,增强了代码的复用性。 * 低耦合:购物车类与具体的促销策略解耦,使得系统更灵活,更容易维护。 * 对于简单的场景,直接在购物车类中添加多个计算方法直观易懂,初学者更容易接受。
缺点 * 策略种类增多时,可能会导致策略接口的家族变得庞大,若策略逻辑差异不大,可能会造成代码冗余。 * 耦合度高:购物车类与具体的促销逻辑紧密耦合,当促销策略发生变化时,必须修改购物车类的代码。 * 扩展困难:若促销策略种类增加,会导致购物车类的代码臃肿,且不利于代码维护。 * 代码复用性差:对于每一种新的促销活动,都需要在购物车类中添加新的方法,无法直接复用现有逻辑。

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

文末

文章到这里就结束了~

相关推荐
枫叶林FYL21 小时前
Agent/Teakenote 系统(Swarm 架构)深度技术报告
架构·策略模式
苏渡苇2 天前
枚举的高级用法——用枚举实现策略模式和状态机
java·单例模式·策略模式·枚举·状态机·enum
harder3214 天前
Swift 面向协议编程的 RMP 模式
开发语言·ios·mvc·swift·策略模式
skywalk81635 天前
esxi8 虚拟机中怎么安装mac os(纯AI回答,未实践)
策略模式·esxi
廖圣平5 天前
从零开始,福袋直播间脚本研究【八】《策略模式》
开发语言·python·bash·策略模式
爱学习 爱分享9 天前
简单工厂模式和策略模式的区别
简单工厂模式·策略模式
xcntime12 天前
Python中print函数如何实现不换行输出?
策略模式
青春易逝丶13 天前
策略模式
java·开发语言·策略模式
sg_knight13 天前
设计模式实战:策略模式(Strategy)
java·开发语言·python·设计模式·重构·架构·策略模式
liangshanbo121513 天前
[特殊字符] macOS 上的 zoxide:智能目录跳转终极指南
macos·策略模式