Java 枚举与策略模式、函数式接口的结合:实现高内聚低耦合的设计

182 阅读4分钟

大家好,今天咱们来聊聊Java里的枚举、策略模式和函数式接口这三个玩意儿怎么搞到一起,搞出一个高内聚低耦合的设计。听起来是不是有点高大上?别急,咱们慢慢来,保证你能听懂,还能用得上。

首先,咱们得知道什么是枚举。枚举,说白了就是一组固定的常量。比如你有个需求,要表示一周的七天,那你就可以用枚举来定义:

public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

这样,你在代码里就可以直接用Day.MONDAY来表示星期一,不用再写一堆public static final int MONDAY = 1;这样的代码了。枚举的好处就是类型安全,编译器会帮你检查,避免你写错。

接下来,咱们说说策略模式。策略模式是一种行为设计模式,它允许你定义一系列算法,把它们封装起来,并且使它们可以互相替换。说白了,就是你有一堆不同的实现方式,但你不想在代码里写一堆if-else或者switch-case来判断用哪个实现。策略模式就是为了解决这个问题。

举个例子,假设你有个需求,要根据不同的用户类型来计算折扣。你可以定义一个DiscountStrategy接口:

public interface DiscountStrategy {
    double applyDiscount(double price);
}

然后,你可以为每种用户类型实现一个具体的策略:

public class RegularCustomerDiscount implements DiscountStrategy {
    @Override
    public double applyDiscount(double price) {
        return price * 0.9// 普通用户打9折
    }
}

public class VIPCustomerDiscount implements DiscountStrategy {
    @Override
    public double applyDiscount(double price) {
        return price * 0.8// VIP用户打8折
    }
}

这样,你在代码里就可以根据用户类型来选择合适的策略,而不需要写一堆if-else

好了,现在咱们有了枚举和策略模式,接下来就是函数式接口。函数式接口是Java 8引入的一个新特性,它就是一个只有一个抽象方法的接口。Java 8里有很多内置的函数式接口,比如ConsumerSupplierFunction等等。你可以用Lambda表达式或者方法引用来实现这些接口。

那么,怎么把枚举、策略模式和函数式接口结合起来呢?咱们来看个例子。

假设你有个需求,要根据不同的操作类型来执行不同的操作。你可以定义一个枚举,每个枚举值都对应一个操作:

public enum Operation {
    ADD((x, y) -> x + y),
    SUBTRACT((x, y) -> x - y),
    MULTIPLY((x, y) -> x * y),
    DIVIDE((x, y) -> x / y);

    private final BiFunction<Double, Double, Double> operation;

    Operation(BiFunction<Double, Double, Double> operation) {
        this.operation = operation;
    }

    public double apply(double x, double y) {
        return operation.apply(x, y);
    }
}

这里,我们用了BiFunction这个函数式接口,它接受两个参数,返回一个结果。每个枚举值都对应一个BiFunction的实现,比如ADD对应的是(x, y) -> x + ySUBTRACT对应的是(x, y) -> x - y,以此类推。

这样,你在代码里就可以这样用:

double result = Operation.ADD.apply(23); // 结果是5
double result2 = Operation.MULTIPLY.apply(23); // 结果是6

看到没?这样一来,代码就变得非常简洁,而且高内聚低耦合。每个操作的具体实现都封装在枚举里,外面只需要调用apply方法就行了。

再举个例子,假设你有个需求,要根据不同的日志级别来记录日志。你可以定义一个枚举,每个枚举值都对应一个日志记录策略:

public enum LogLevel {
    INFO(message -> System.out.println("INFO: " + message)),
    WARN(message -> System.out.println("WARN: " + message)),
    ERROR(message -> System.err.println("ERROR: " + message));

    private final Consumer<String> logStrategy;

    LogLevel(Consumer<String> logStrategy) {
        this.logStrategy = logStrategy;
    }

    public void log(String message) {
        logStrategy.accept(message);
    }
}

这里,我们用了Consumer这个函数式接口,它接受一个参数,没有返回值。每个枚举值都对应一个Consumer的实现,比如INFO对应的是message -> System.out.println("INFO: " + message)WARN对应的是message -> System.out.println("WARN: " + message)ERROR对应的是message -> System.err.println("ERROR: " + message)

这样,你在代码里就可以这样用:

LogLevel.INFO.log("This is an info message."); // 输出:INFO: This is an info message.
LogLevel.ERROR.log("This is an error message."); // 输出:ERROR: This is an error message.

这样一来,日志记录的策略就封装在枚举里,外面只需要调用log方法就行了,代码非常简洁。

总结一下,枚举、策略模式和函数式接口的结合,可以让你的代码更加高内聚低耦合。枚举帮你定义一组固定的常量,策略模式帮你封装不同的实现,函数式接口帮你简化代码。三者结合,威力无穷。

好了,今天就聊到这里。如果你觉得这篇文章对你有帮助,别忘了点赞、转发、关注三连!咱们下期再见!