Java抽象类与接口的现代应用实践(Java 17+)
在Java 17及后续版本中,抽象类和接口的应用结合了记录类(Record)、密封类(Sealed Class)、模式匹配(Pattern Matching)等新特性,为代码设计带来了更多可能。下面通过实际案例展示这些技术的综合应用。
一、抽象类的现代应用:结合密封类与模式匹配
案例背景:设计一个图形处理系统,支持计算不同形状的面积和周长。
// 密封抽象类定义图形层次结构
public abstract sealed class Shape permits Circle, Rectangle, Triangle {
// 抽象方法:计算面积
public abstract double area();
// 抽象方法:计算周长
public abstract double perimeter();
// 默认方法:显示图形信息
public void displayInfo() {
System.out.printf("%s - 面积: %.2f, 周长: %.2f%n",
getClass().getSimpleName(), area(), perimeter());
}
// 静态工厂方法:使用模式匹配处理不同形状
public static void processShape(Shape shape) {
switch (shape) {
case Circle c -> System.out.println("圆形: 半径=" + c.radius());
case Rectangle r -> System.out.println("矩形: 长=" + r.length() + ", 宽=" + r.width());
case Triangle t -> System.out.println("三角形: 边长=" + t.sideA() + ", " + t.sideB() + ", " + t.sideC());
}
}
}
// 使用记录类实现具体形状
public record Circle(double radius) implements Shape {
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
}
public record Rectangle(double length, double width) implements Shape {
@Override
public double area() {
return length * width;
}
@Override
public double perimeter() {
return 2 * (length + width);
}
}
public record Triangle(double sideA, double sideB, double sideC) implements Shape {
@Override
public double area() {
double s = (sideA + sideB + sideC) / 2;
return Math.sqrt(s * (s - sideA) * (s - sideB) * (s - sideC));
}
@Override
public double perimeter() {
return sideA + sideB + sideC;
}
}
// 主程序演示
public class ShapeDemo {
public static void main(String[] args) {
Shape circle = new Circle(5.0);
Shape rectangle = new Rectangle(4.0, 6.0);
Shape triangle = new Triangle(3.0, 4.0, 5.0);
circle.displayInfo();
rectangle.displayInfo();
triangle.displayInfo();
Shape.processShape(circle);
}
}
技术亮点:
- 密封抽象类:使用
sealed
关键字限制子类范围,增强类型安全性 - 记录类实现:简化了数据类的定义,自动生成构造器、访问器和
equals/hashCode
- 模式匹配:在
switch
语句中直接解构记录类的属性
二、接口的现代应用:函数式接口与默认方法组合
案例背景:实现一个简单的事件处理框架,支持事件发布和订阅。
import java.util.*;
import java.util.function.Consumer;
// 事件总线接口 - 使用函数式接口和默认方法
public interface EventBus {
// 注册事件监听器
void registerListener(String eventType, Consumer<Object> listener);
// 发布事件
void publishEvent(String eventType, Object data);
// 默认方法:批量注册多个事件类型的监听器
default void registerListeners(Map<String, Consumer<Object>> listeners) {
listeners.forEach(this::registerListener);
}
// 静态工厂方法:创建基于内存的事件总线实现
static EventBus inMemoryEventBus() {
return new InMemoryEventBus();
}
}
// 内存实现的事件总线
final class InMemoryEventBus implements EventBus {
private final Map<String, List<Consumer<Object>>> listeners = new HashMap<>();
@Override
public void registerListener(String eventType, Consumer<Object> listener) {
listeners.computeIfAbsent(eventType, k -> new ArrayList<>())
.add(listener);
}
@Override
public void publishEvent(String eventType, Object data) {
listeners.getOrDefault(eventType, Collections.emptyList())
.forEach(listener -> listener.accept(data));
}
}
// 应用示例
public class EventBusDemo {
public static void main(String[] args) {
EventBus bus = EventBus.inMemoryEventBus();
// 注册事件监听器
bus.registerListener("user.login", data ->
System.out.printf("用户登录: %s%n", data));
bus.registerListener("order.create", data ->
System.out.printf("订单创建: %s%n", data));
// 发布事件
bus.publishEvent("user.login", "testUser");
bus.publishEvent("order.create", Map.of("id", "ORD123", "amount", 99.99));
}
}
技术亮点:
- 函数式接口:使用
Consumer<T>
作为事件监听器类型 - 默认方法扩展:提供
registerListeners
默认方法简化批量注册 - 静态工厂方法:通过
inMemoryEventBus()
创建实例,隐藏实现细节
三、混合使用抽象类与接口:实现复杂业务逻辑
案例背景:设计一个电商促销系统,支持不同类型的折扣策略。
import java.math.BigDecimal;
import java.util.*;
// 定义折扣策略接口
@FunctionalInterface
public interface DiscountStrategy {
BigDecimal applyDiscount(BigDecimal originalPrice);
// 默认方法:组合多个折扣策略
default DiscountStrategy combine(DiscountStrategy next) {
return price -> next.applyDiscount(this.applyDiscount(price));
}
// 静态方法:创建百分比折扣策略
static DiscountStrategy percentage(double percent) {
return price -> price.multiply(BigDecimal.valueOf(1 - percent / 100));
}
// 静态方法:创建固定金额折扣策略
static DiscountStrategy fixedAmount(BigDecimal amount) {
return price -> price.subtract(amount).max(BigDecimal.ZERO);
}
}
// 抽象促销类
public abstract class Promotion {
private final String name;
private final DiscountStrategy strategy;
protected Promotion(String name, DiscountStrategy strategy) {
this.name = name;
this.strategy = strategy;
}
public String getName() {
return name;
}
public BigDecimal calculateDiscountedPrice(BigDecimal originalPrice) {
return strategy.applyDiscount(originalPrice);
}
// 抽象方法:检查促销是否适用于给定商品
public abstract boolean isApplicable(Product product);
}
// 具体促销实现
public class HolidayPromotion extends Promotion {
private final Set<String> applicableCategories;
public HolidayPromotion(String name, double discountPercent, String... categories) {
super(name, DiscountStrategy.percentage(discountPercent));
this.applicableCategories = Set.of(categories);
}
@Override
public boolean isApplicable(Product product) {
return applicableCategories.contains(product.getCategory());
}
}
// 商品类
public record Product(String id, String name, String category, BigDecimal price) {
}
// 购物车类
public class ShoppingCart {
private final List<Product> items = new ArrayList<>();
private final List<Promotion> promotions = new ArrayList<>();
public void addItem(Product product) {
items.add(product);
}
public void applyPromotion(Promotion promotion) {
promotions.add(promotion);
}
public BigDecimal calculateTotal() {
return items.stream()
.map(product -> {
// 查找适用的促销并应用最大折扣
Optional<Promotion> bestPromotion = promotions.stream()
.filter(p -> p.isApplicable(product))
.max(Comparator.comparing(p ->
product.price().subtract(p.calculateDiscountedPrice(product.price()))));
return bestPromotion.map(p -> p.calculateDiscountedPrice(product.price()))
.orElse(product.price());
})
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
// 演示程序
public class EcommerceDemo {
public static void main(String[] args) {
Product laptop = new Product("P001", "笔记本电脑", "电子产品", new BigDecimal("5999"));
Product headphones = new Product("P002", "耳机", "电子产品", new BigDecimal("899"));
Product book = new Product("P003", "Java编程思想", "图书", new BigDecimal("129"));
ShoppingCart cart = new ShoppingCart();
cart.addItem(laptop);
cart.addItem(headphones);
cart.addItem(book);
// 添加促销活动
cart.applyPromotion(new HolidayPromotion("国庆促销", 15, "电子产品"));
cart.applyPromotion(new HolidayPromotion("书香节", 20, "图书"));
// 计算折扣后总价
BigDecimal total = cart.calculateTotal();
System.out.printf("原价: ¥%.2f%n", cart.calculateTotalWithoutDiscounts());
System.out.printf("折扣后总价: ¥%.2f%n", total);
}
}
技术亮点:
- 函数式接口设计:
DiscountStrategy
接口支持策略组合和静态工厂方法 - 抽象类封装公共行为:
Promotion
类管理折扣策略并定义抽象适用性检查 - Java Stream API:在
ShoppingCart
中使用流式处理计算最优折扣
四、实战技巧总结
- 使用密封类增强类型安全:限制抽象类的子类范围,使代码更具可维护性
- 函数式接口简化回调:利用Java内置函数式接口减少样板代码
- 默认方法渐进式增强:在不破坏现有实现的前提下扩展接口功能
- 记录类替代数据类:对于简单数据载体,优先使用记录类而非普通类
- 模式匹配优化类型检查:简化条件分支中的类型判断和属性提取
通过结合这些现代Java特性,可以构建更加简洁、灵活且类型安全的抽象类和接口设计,充分发挥Java语言的优势。
Java 抽象类,Java 接口,Java17 新特性,面向对象编程,抽象类应用,接口实现,现代 Java 开发,Java 开发实践,多态性,抽象方法,default 方法,static 方法,接口隔离原则,抽象类设计,Java 编程规范
代码获取方式
https://pan.quark.cn/s/14fcf913bae6