接口多态:神奇宝贝的「技能盲盒」

咱都知道Java是面向对象的,多态是它的核心特性。我觉得多态最有意思的地方在于「晚绑定」——就像拆盲盒,不到最后一步不知道里面是啥。

举个栗子🌰:
你养了只神奇宝贝,代码写成PocketMon pocketMon = new Pikaqiu();,调用pocketMon.releaseSkill()时,你知道是「电击」。但如果代码改成这样:

Properties pro = new Properties();
pro.load(new FileInputStream("pocketmon.properties")); 
PocketMon pocketMon = (PocketMon) Class.forName(pro.getProperty("nextPocketMon")).newInstance();
pocketMon.releaseSkill();

这时候你猜它会放啥技能?看pocketmon.properties里写的是「皮卡丘」?但运行时我可能偷偷改成「喷火龙」——JVM不到执行这行代码,根本不知道具体是哪只宝可梦在放技能。

这就是多态的魅力:代码写死了,但实际执行时的行为由运行时的对象决定。原理上,JVM得在运行时查方法表,匹配当前对象的具体实现。所以理论上,多态的性能比直接写死(早绑定)差点——毕竟得「现查」嘛。但多态是设计模式的灵魂,为了灵活性,这点性能牺牲大部分时候都值。

方法多态:给可乐鸡翅留个「自定义步骤」

之前山寨Stream API时,我生造了个「方法多态」的概念。其实就是用函数式接口把「不确定的步骤」占个坑,让调用者自己填逻辑——这更贴近函数式编程的思路。

举个做菜的例子:做可乐鸡翅,关键步骤是「放鸡翅」和「倒可乐」,但顺序因人而异。有人喜欢先放鸡翅再倒可乐,有人反过来。

要是按传统写法,步骤全写死:

public static CokaChickenWing cook(Chicken chicken, Coka coka) {
    1. 放油、放姜;
    2. 放鸡翅;
    3. 倒可乐;
    return 可乐鸡翅;
}

但众口难调啊!这时候可以用「方法多态」——定义个函数式接口占坑,让调用者自己决定步骤:

// 定义接口:占住「步骤2-3」的坑
@FunctionalInterface
interface TwoStep {
    void execute(Chicken chicken, Coka coka);
}

// 通用烹饪方法
public static CokaChickenWing cook(Chicken chicken, Coka coka, TwoStep twoStep) {
    1. 放油、放姜;
    twoStep.execute(chicken, coka); // 调用者填步骤
    return 可乐鸡翅;
}

调用时,想先放鸡翅就传:

cook(鸡翅, 可乐, (chicken, coka) -> {
    2. 放鸡翅;
    3. 倒可乐;
});

想先倒可乐就传:

cook(鸡翅, 可乐, (chicken, coka) -> {
    2. 倒可乐;
    3. 放鸡翅;
});

这就是「方法多态」——用函数式接口把不确定的逻辑抽象成参数,调用时通过Lambda传入具体实现。

晚绑定的亲兄弟:模板方法模式

设计模式里,策略模式和模板方法模式都用了晚绑定,但玩法不太一样。策略模式是用接口占坑,传不同实现类;模板方法模式更“抠细节”,用抽象类定骨架,把变化的部分拆成抽象方法,让子类填坑。

举个验证码发送的例子🌰:
不管是短信验证码还是邮箱验证码,流程大差不差:生成验证码→存Session→发送。但「发送」的具体方式不同(短信走阿里云,邮箱走QQ)。

用模板方法模式设计:

// 抽象类:定好流程骨架
public abstract class AbstractValidateCodeSender {
    // 主流程(不变的部分)
    public void sendValidateCode() {
        String code = generateValidateCode(); // 生成验证码(固定)
        saveToSession(code); // 存Session(固定)
        sendCode(code); // 发送(变化的部分,抽象方法)
    }

    // 生成验证码(固定逻辑)
    protected String generateValidateCode() {
        return "123456"; 
    }

    // 存Session(固定逻辑)
    private void saveToSession(String code) {
        // 具体实现...
    }

    // 抽象方法:发送逻辑由子类填坑
    protected abstract void sendCode(String code);
}

子类只需要填「发送」的坑:

// 短信验证码发送器
public class SmsValidateCodeSender extends AbstractValidateCodeSender {
    @Override
    protected void sendCode(String code) {
        // 调用阿里云短信API发送
        System.out.println("短信发送验证码:" + code);
    }
}

// 邮箱验证码发送器
public class EmailValidateCodeSender extends AbstractValidateCodeSender {
    @Override
    protected void sendCode(String code) {
        // 调用QQ邮箱API发送
        System.out.println("邮箱发送验证码:" + code);
    }
}

用的时候,想发邮件就new EmailValidateCodeSender,想发短信就new SmsValidateCodeSender——流程骨架由抽象类定死,变化的部分晚绑定到子类实现。

总结

  • 接口多态:运行时才确定具体调用哪个实现(像拆神奇宝贝盲盒)。

  • 方法多态:用函数式接口占坑,Lambda传逻辑(可乐鸡翅的自定义步骤)。

  • 模板方法模式:抽象类定骨架,子类填变化的坑(验证码发送的通用流程)。

多态的本质是「晚绑定」,牺牲点性能换灵活性——这世上哪有十全十美的事儿?设计时根据场景选合适的模式,才是关键~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

剽悍一小兔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值