場景:主程序不依賴具體實現類,通過配置/參數指定類名,利用反射動態實例化,實現「不修改主代碼擴展新實現」(開閉原則)。
package com.example.vehicle;
public interface Vehicle {
/**
* 計算行駛速度
* @param a 參數A
* @param b 參數B
* @param c 參數C
* @return 速度 km/h
*/
double calculateSpeed(double a, double b, double c);
}
package com.example.vehicle.impl;
public class Car implements Vehicle {
@Override
public double calculateSpeed(double a, double b, double c) {
return a * b / c; // 汽車速度公式
}
}
public class Plane implements Vehicle {
@Override
public double calculateSpeed(double a, double b, double c) {
return a + b + c; // 飛機速度公式
}
}
// 新增 Ship 無需修改任何現有代碼
public class Ship implements Vehicle {
@Override
public double calculateSpeed(double a, double b, double c) {
return (a + b) * c / 10; // 船隻速度公式
}
}
package com.example.main;
import com.example.vehicle.Vehicle;
public class TravelTimeCalculator {
public static void main(String[] args) {
if (args.length != 4) {
System.err.println("用法: java TravelTimeCalculator ");
System.err.println("示例: java TravelTimeCalculator com.example.vehicle.impl.Car 100 45 67");
return;
}
String className = args[0];
double a = Double.parseDouble(args[1]);
double b = Double.parseDouble(args[2]);
double c = Double.parseDouble(args[3]);
try {
// 關鍵:反射動態實例化
Class> clazz = Class.forName(className);
Vehicle vehicle = (Vehicle) clazz.getDeclaredConstructor().newInstance();
double speed = vehicle.calculateSpeed(a, b, c);
double hours = 1000.0 / speed; // 固定距離 1000km
System.out.printf("交通工具: %s%n", className);
System.out.printf("參數: A=%.2f, B=%.2f, C=%.2f%n", a, b, c);
System.out.printf("平均速度: %.2f km/h%n", speed);
System.out.printf("行駛 1000km 需時: %.2f 小時%n", hours);
} catch (ClassNotFoundException e) {
System.err.println("找不到類: " + className);
} catch (Exception e) {
System.err.println("實例化失敗: " + e.getMessage());
e.printStackTrace();
}
}
}
$ java TravelTimeCalculator com.example.vehicle.impl.Car 100 45 67
交通工具: com.example.vehicle.impl.Car
參數: A=100.00, B=45.00, C=67.00
平均速度: 67.16 km/h
行駛 1000km 需時: 14.89 小時
$ java TravelTimeCalculator com.example.vehicle.impl.Plane 130 45 67
交通工具: com.example.vehicle.impl.Plane
參數: A=130.00, B=45.00, C=67.00
平均速度: 242.00 km/h
行駛 1000km 需時: 4.13 小時
場景:同一操作有多種算法/行為,通過傳入不同接口實現動態切換行為,避免大量 if-else/switch。
// 統一接口
public interface ExpansionCard {
void initialize(); // 初始化卡片
}
// 具體實現
public class GraphicsCard implements ExpansionCard {
@Override public void initialize() { System.out.println("顯卡初始化: GPU 驅動加載、VRAM 檢測"); }
}
public class NetworkCard implements ExpansionCard {
@Override public void initialize() { System.out.println("網卡初始化: MAC 地址綁定、協議棧啟動"); }
}
public class SoundCard implements ExpansionCard {
@Override public void initialize() { System.out.println("聲卡初始化: DSP 固件加載、編解碼器就緒"); }
}
// 主板類:接口作為方法參數
public class Motherboard {
public void installCard(ExpansionCard card) { // 關鍵:接口類型參數
System.out.println("主板檢測到擴展卡,開始初始化...");
card.initialize(); // 多態調用,具體行為由傳入實例決定
System.out.println("擴展卡安裝完成。");
}
}
// 客戶端代碼
public class ComputerAssembly {
public static void main(String[] args) {
Motherboard mb = new Motherboard();
mb.installCard(new GraphicsCard()); // 裝顯卡
mb.installCard(new NetworkCard()); // 裝網卡
mb.installCard(new SoundCard()); // 裝聲卡
// 新增 USB 卡無需修改 Motherboard
mb.installCard(new ExpansionCard() {
@Override public void initialize() { System.out.println("USB 控制器初始化"); }
});
}
}
| 維度 | 動態加載多態 | 策略模式參數傳遞 |
|---|---|---|
| 核心機制 | 反射 + Class.forName() | 多態調用 (接口引用指向實現對象) |
| 耦合度 | 極低:主程序完全不依賴實現類 | 低:依賴接口定義,不依賴具體類 |
| 擴展方式 | 新增實現類 + 配置類名 | 新增實現類 + 調用處傳入新實例 |
| 典型場景 | 插件系統、驅動程序、可配置組件 | 算法策略、回調處理器、事件監聽器 |
| 性能 | 首次反射較慢,可緩存 Constructor | 直接調用,JIT 內聯優化極佳 |
| 類型安全 | 運行時才發現 ClassNotFound/Cast 異常 | 編譯期類型檢查,安全 |
// META-INF/services/com.example.vehicle.Vehicle 文件內容:
com.example.vehicle.impl.Car
com.example.vehicle.impl.Plane
com.example.vehicle.impl.Ship
// 代碼加載
ServiceLoader loader = ServiceLoader.load(Vehicle.class);
for (Vehicle v : loader) {
System.out.println("發現實現: " + v.getClass().getName() + " 速度: " + v.calculateSpeed(1,2,3));
}
@Component
public class TravelService {
private final Map vehicles; // 自動注入所有實現 Bean
public TravelService(Map vehicles) {
this.vehicles = vehicles;
}
public double calcTime(String vehicleName, double a, double b, double c) {
Vehicle v = vehicles.get(vehicleName);
if (v == null) throw new IllegalArgumentException("未知交通工具: " + vehicleName);
return 1000 / v.calculateSpeed(a, b, c);
}
}
Interface 是 Java 面向抽象編程的基石。動態加載多態 通過反射打破編譯期依賴,支撐插件化架構;策略模式參數傳遞 利用多態消除條件分支,實現行為動態組合。現代框架(Spring、Dubbo、SPI)進一步將這兩種模式標準化、自動化,開發者應優先使用框架提供的機制(@Autowired、ServiceLoader、@SPI),僅在框架無法覆蓋的邊緣場景手寫反射/多態代碼。