多态:让同一条消息产生千般面孔——从原理到策略模式实战

34 阅读2分钟

一、什么是多态
一句话:同一条消息,被不同对象接收时表现出不同行为。
在 Java 中,实例方法天生就是多态的:

Bird b = new Bird();
Plane p = new Plane();
fly(b); // 挥动翅膀
fly(p); // 启动引擎

fly 方法的“接收者”决定了最终执行哪段代码,而参数则在编译期静态绑定——多态只关心“谁接收消息”,不关心“参数是谁”。

注意:
• static 方法没有多态,它在编译期就与类绑定。
• null instanceof AnyClass 永远返回 false,避免空指针误判。

二、多态带来的设计红利——策略模式

  1. 问题:一段冗长的 if-else 计算折扣
switch(strategy){
    case "NoDiscount": ...
    case "95": ...
    case "VIP": ...
}

新增一种折扣就要改方法,违背开闭原则。

  1. 解决:把“变化”封装成策略家族
    • 抽象策略
public interface DiscountStrategy {
    int discount(int price, User user);
}

• 具体策略

public class NoDiscountStrategy implements DiscountStrategy {
    public int discount(int price, User user) { return price; }
}
public class Vip95Strategy implements DiscountStrategy {
    public int discount(int price, User user) {
        return user.isVip() ? (int)(price * 0.95) : price;
    }
}

• 上下文

public class PriceCalculator {
    public int calculate(DiscountStrategy strategy, int price, User user) {
        return strategy.discount(price, user);
    }
}

新增策略 = 新建一个类,上下文代码零修改,彻底解耦。

三、JDK 中的策略模式范例——线程池拒绝策略
ThreadPoolExecutor 最后一个参数 RejectedExecutionHandler 就是策略接口:

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

JDK 自带 4 种实现:AbortPolicy / CallerRunsPolicy / DiscardOldestPolicy / DiscardPolicy。
• 想自定义?只需实现接口,线程池无需任何改动。
• 面试高频:为什么线程池要抽象出 RejectedExecutionHandler?答案——策略模式带来的独立变化与松耦合。

四、用多态重构“胖”代码
实际项目中,任何出现大片 if-else/switch 且分支逻辑与业务强耦合的地方,都可以:

  1. 提取公共接口或抽象类;
  2. 把每个分支变成具体策略;
  3. 通过工厂 + 多态注入。
    IntelliJ IDEA 的 Diagrams 功能可以一键查看继承树,辅助我们验证设计是否合理。

五、金额表示的友情提醒
金融场景千万别用 double!1.0-0.9≠0.1。统一用 BigDecimal 或“分”为单位 long 型,避免精度灾难。