Java二次分发

java 复制代码
package com.example.demo;

public class UserDemo {
  public static void main(String[] args) {
    Driver a = new FemaleDriver();
    Driver b = new MaleDriver();
    Vehicle x = new Car();
    Vehicle y = new Bus();
    a.drives(x);
    b.drives(y);
  }
}

abstract class Vehicle {
  private String type;
  public Vehicle() {};
  public Vehicle(String s) {
    type = s;
  };
  public abstract void driveByFemaleDriver();
  public abstract void driveByMaleDriver();
}

class Bus extends Vehicle {
  public Bus() {}
  public void driveByFemaleDriver(){
    System.out.println("bus drive by female driver");
  }
  public void driveByMaleDriver() {
    System.out.println("bus drive by male driver");
  }
}

class Car extends Vehicle {
  public Car() {}
  public void driveByFemaleDriver(){
    System.out.println("bus drive by female driver");
  }
  public void driveByMaleDriver() {
    System.out.println("bus drive by male driver");
  }
}

abstract class Driver{
  public Driver() {}
  public abstract void drives(Vehicle v);
}

// 二次分发
class FemaleDriver extends Driver {
  public FemaleDriver() {}
  public void drives(Vehicle v) {
    v.driveByFemaleDriver();
  }
}
class MaleDriver extends Driver {
  public MaleDriver() {}
  public void drives(Vehicle v) {
    v.driveByMaleDriver();
  }
}

这段代码演示了一个经典的设计模式------双分派(Double Dispatch),我来逐层解释:


📐 整体类结构

#mermaid-svg-ik2oUyw5tiUM60vP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ik2oUyw5tiUM60vP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ik2oUyw5tiUM60vP .error-icon{fill:#552222;}#mermaid-svg-ik2oUyw5tiUM60vP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ik2oUyw5tiUM60vP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ik2oUyw5tiUM60vP .marker.cross{stroke:#333333;}#mermaid-svg-ik2oUyw5tiUM60vP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ik2oUyw5tiUM60vP p{margin:0;}#mermaid-svg-ik2oUyw5tiUM60vP g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-ik2oUyw5tiUM60vP g.classGroup text .title{font-weight:bolder;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster-label text{fill:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster-label span{color:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster-label span p{background-color:transparent;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster text{fill:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster span{color:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .nodeLabel,#mermaid-svg-ik2oUyw5tiUM60vP .edgeLabel{color:#131300;}#mermaid-svg-ik2oUyw5tiUM60vP .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-ik2oUyw5tiUM60vP .label text{fill:#131300;}#mermaid-svg-ik2oUyw5tiUM60vP .labelBkg{background:#ECECFF;}#mermaid-svg-ik2oUyw5tiUM60vP .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-ik2oUyw5tiUM60vP .classTitle{font-weight:bolder;}#mermaid-svg-ik2oUyw5tiUM60vP .node rect,#mermaid-svg-ik2oUyw5tiUM60vP .node circle,#mermaid-svg-ik2oUyw5tiUM60vP .node ellipse,#mermaid-svg-ik2oUyw5tiUM60vP .node polygon,#mermaid-svg-ik2oUyw5tiUM60vP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ik2oUyw5tiUM60vP .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP g.clickable{cursor:pointer;}#mermaid-svg-ik2oUyw5tiUM60vP g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-ik2oUyw5tiUM60vP g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-ik2oUyw5tiUM60vP .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-ik2oUyw5tiUM60vP .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-ik2oUyw5tiUM60vP .dashed-line{stroke-dasharray:3;}#mermaid-svg-ik2oUyw5tiUM60vP .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-ik2oUyw5tiUM60vP #compositionStart,#mermaid-svg-ik2oUyw5tiUM60vP .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #compositionEnd,#mermaid-svg-ik2oUyw5tiUM60vP .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #dependencyStart,#mermaid-svg-ik2oUyw5tiUM60vP .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #dependencyStart,#mermaid-svg-ik2oUyw5tiUM60vP .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #extensionStart,#mermaid-svg-ik2oUyw5tiUM60vP .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #extensionEnd,#mermaid-svg-ik2oUyw5tiUM60vP .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #aggregationStart,#mermaid-svg-ik2oUyw5tiUM60vP .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #aggregationEnd,#mermaid-svg-ik2oUyw5tiUM60vP .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #lollipopStart,#mermaid-svg-ik2oUyw5tiUM60vP .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #lollipopEnd,#mermaid-svg-ik2oUyw5tiUM60vP .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-ik2oUyw5tiUM60vP .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ik2oUyw5tiUM60vP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ik2oUyw5tiUM60vP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} <<abstract>>
Vehicle
-String type
+driveByFemaleDriver()
+driveByMaleDriver()
<<abstract>>
Driver
+drives(Vehicle v)
Bus
Car
FemaleDriver
MaleDriver


🔍 逐段解析

第一层:抽象类 Vehicle(载具)

java 复制代码
abstract class Vehicle {
    private String type;
    public Vehicle() {};
    public Vehicle(String s) { type = s; }

    // 定义两个抽象方法:谁来开,由子类实现
    public abstract void driveByFemaleDriver();
    public abstract void driveByMaleDriver();
}
  • abstract 表示这是抽象类,不能直接 new
  • 声明了两个抽象方法,强制子类(Car、Bus)必须实现

第二层:CarBus 实现具体行为

java 复制代码
class Bus extends Vehicle {
    public void driveByFemaleDriver() {
        System.out.println("bus drive by female driver");
    }
    public void driveByMaleDriver() {
        System.out.println("bus drive by male driver");
    }
}

class Car extends Vehicle {
    // 同理,实现自己的驾驶行为
}

第三层:抽象类 Driver(司机)

java 复制代码
abstract class Driver {
    public abstract void drives(Vehicle v);  // 接收一个载具
}

第四层:FemaleDriverMaleDriver 实现分派

java 复制代码
class FemaleDriver extends Driver {
    public void drives(Vehicle v) {
        v.driveByFemaleDriver();  // 调用载具上"女性驾驶"方法
    }
}

class MaleDriver extends Driver {
    public void drives(Vehicle v) {
        v.driveByMaleDriver();    // 调用载具上"男性驾驶"方法
    }
}

第五层:主方法执行

java 复制代码
Driver a = new FemaleDriver();
Driver b = new MaleDriver();
Vehicle x = new Car();
Vehicle y = new Bus();

a.drives(x);  // FemaleDriver.drives(Car)  → Car.driveByFemaleDriver()
b.drives(y);  // MaleDriver.drives(Bus)    → Bus.driveByMaleDriver()

🎯 核心:什么是双分派?

Java 本身只支持单分派 (只根据调用者的类型决定执行哪个方法),但这段代码通过两次多态调用模拟了双分派:

复制代码
第一次分派:根据 Driver 的实际类型(Female / Male)
     ↓
a.drives(x)  →  FemaleDriver.drives()

第二次分派:根据 Vehicle 的实际类型(Car / Bus)
     ↓
v.driveByFemaleDriver()  →  Car.driveByFemaleDriver()

用表格表示最终会调用哪个方法:

Car Bus
FemaleDriver Car.driveByFemaleDriver() Bus.driveByFemaleDriver()
MaleDriver Car.driveByMaleDriver() Bus.driveByMaleDriver()

💡 这个模式解决了什么问题?

不用双分派的写法(反例):

java 复制代码
// ❌ 用 if-else 判断类型,难以扩展
public void drives(Vehicle v) {
    if (v instanceof Car) {
        System.out.println("female drives car");
    } else if (v instanceof Bus) {
        System.out.println("female drives bus");
    }
    // 每次新增车辆类型都要修改这里 ❌
}

用双分派的写法:

java 复制代码
// ✅ 新增一种车辆,只需新建子类并实现两个方法,无需改动 Driver
class Truck extends Vehicle {
    public void driveByFemaleDriver() { ... }
    public void driveByMaleDriver() { ... }
}

📝 总结

概念 说明
抽象类 VehicleDriver 定义骨架,不能直接实例化
多态 父类引用指向子类对象(Driver a = new FemaleDriver()
双分派 通过两次虚方法调用,根据司机类型 + 载具类型共同决定最终行为
设计目的 避免 instanceof 判断,新增类型时只需扩展,不修改已有代码(开闭原则)
相关推荐
半亩码田10 分钟前
C#转Python第3.1篇:Python 的 class 没有访问修饰符?面向对象的另一条路
开发语言·python·c#
真上帝的左手1 小时前
10. 软件设计&架构-Spring Security 7 整合CAS SSO 单点登录
java·spring·架构·sso
Wzx1980121 小时前
python沙箱和docker沙箱你选对了吗?
开发语言·python·docker
牧羊人.3331 小时前
Python 办公自动化从入门到入土|09 数据容器之字典
开发语言·python
Zane19941 小时前
单例线程安全、生产者消费者、死锁:并发面试三连问串讲
java·后端
小僧景贤1 小时前
嵌入式C语言 第二篇:基础语法|嵌入式C与标准C的核心差异
c语言·开发语言·嵌入式c语言
阿pin1 小时前
Android随笔-AIDL
android·开发语言·aidl
云烟成雨TD2 小时前
Micrometer 系列【42】链路追踪:Span 体系 | 核心 API
java·链路追踪·micrometer
Gorway2 小时前
理解 Spring 依赖注入:从构造器注入到集合与条件 Bean
java·后端
LiLiYuan.2 小时前
【字符串常量池】
java·开发语言·面试