第 6 章 · 接口、抽象类、enum 与 record
本章目标:理解接口与抽象类的差异与选用;掌握 implements、默认方法与静态接口方法;熟练使用 enum 表达有限状态;了解 record(Java 16+)简化数据载体;扩展 toolkit-demo 的可定价与订单状态模型;对照 python-dev 的 abc 与枚举。
学时建议:4 小时(含 1.5 小时跟练)
前置:完成 java-dev ch05;建议了解 python-dev 中 Enum 与抽象基类概念。
6.1 场景说明:定价策略与订单状态
toolkit-demo 需要:
- 多种定价策略(标准价、会员价、批发价)——用接口统一
priceFor。 - 订单状态有限集合 —— 用
enum替代字符串常量。 - 订单摘要只读数据 —— 用
record承载。
learn-java/toolkit-demo/src/main/java/demo/contract/
├── Pricable.java
├── PricingStrategy.java + 实现类
├── OrderStatus.java
├── OrderSummary.java (record)
└── PricingDemo.java
6.2 接口与抽象类
接口定义契约,支持 implements 多实现;Java 8+ 可有 default/static 方法。抽象类可有字段与构造器,适合模板方法。
| 抽象类 | 接口 |
|---|---|
| 单继承、可有实现 | 多实现、契约为主 |
| 共享状态与代码 | 能力标记、策略 |
选用:共享代码用抽象类;多种可替换策略用接口(见 6.3 完整实现)。
6.3 定价策略完整实现
Pricable.java
package demo.contract;
public interface Pricable {
String getSku();
double getBasePrice();
}
PricingStrategy.java
package demo.contract;
public interface PricingStrategy {
double priceFor(Pricable item, int quantity);
default double lineTotal(Pricable item, int quantity) {
if (quantity <= 0) {
return 0.0;
}
return priceFor(item, quantity) * quantity;
}
}
StandardPricing.java
package demo.contract;
public class StandardPricing implements PricingStrategy {
@Override
public double priceFor(Pricable item, int quantity) {
return item.getBasePrice();
}
}
MemberPricing.java
package demo.contract;
public class MemberPricing implements PricingStrategy {
private final double rate;
public MemberPricing(double rate) {
this.rate = rate;
}
@Override
public double priceFor(Pricable item, int quantity) {
return item.getBasePrice() * rate;
}
}
AbstractBulkPricing.java(模板方法基类)
package demo.contract;
/**
* 批量定价抽象基类 — 模板方法模式:
* priceFor 固定「取基价 → 按数量计价」流程,
* 具体计价规则交由子类 applyRate 实现。
*/
public abstract class AbstractBulkPricing implements PricingStrategy {
private final int threshold;
private final double rate;
protected AbstractBulkPricing(int threshold, double rate) {
if (threshold <= 0) {
throw new IllegalArgumentException("阈值须为正数:" + threshold);
}
if (rate <= 0 || rate > 1) {
throw new IllegalArgumentException("费率须在 (0,1]:" + rate);
}
this.threshold = threshold;
this.rate = rate;
}
protected int getThreshold() {
return threshold;
}
protected double getRate() {
return rate;
}
/** 模板方法:声明为 final,防止子类破坏固定流程 */
@Override
public final double priceFor(Pricable item, int quantity) {
double base = item.getBasePrice();
return applyRate(base, quantity);
}
/** 子类实现:根据数量决定是否应用费率 */
protected abstract double applyRate(double base, int quantity);
}
BulkPricing.java
package demo.contract;
public class BulkPricing extends AbstractBulkPricing {
public BulkPricing(int threshold, double rate) {
super(threshold, rate);
}
@Override
protected double applyRate(double base, int quantity) {
return quantity >= getThreshold() ? base * getRate() : base;
}
}
AbstractBulkPricing 的 priceFor 是模板方法(final,固定流程),applyRate 是钩子方法(abstract,子类填规则)——这是抽象类区别于接口的典型用法:接口定契约,抽象类定流程。
SimpleItem.java(Pricable 实现)
package demo.contract;
public class SimpleItem implements Pricable {
private final String sku;
private final String name;
private final double basePrice;
public SimpleItem(String sku, String name, double basePrice) {
this.sku = sku;
this.name = name;
this.basePrice = basePrice;
}
@Override
public String getSku() {
return sku;
}
@Override
public double getBasePrice() {
return basePrice;
}
public String getName() {
return name;
}
}