C# 為單一繼承語言,一個類別只能繼承一個基底類別。但現實領域模型常需組合多種行為(如「卡車」同時具備「車輛」與「工程車輛」特性)。本文探討如何透過多重介面實作與顯式介面實作,優雅解決此設計難題。
abstract class Vehicle { public abstract void Accelerate(); public abstract void Stop(); }
class ConstructionVehicle { public void ExecuteDump() {} public void TurnOnBackUpSound() {} }
// 無法同時繼承 Vehicle 與 ConstructionVehicle
interface IVehicle
{
void Accelerate();
void Stop();
void TurnOnBackUpSound(); // 共同方法
}
interface IConstructionVehicle
{
void ExecuteDump();
void TurnOnBackUpSound(); // 同名方法
}
當多個介面擁有相同簽章方法時,類別可透過介面名稱限定分別實作:
public class DumpTruck : IVehicle, IConstructionVehicle
{
// IVehicle 版本
void IVehicle.TurnOnBackUpSound()
{
Console.WriteLine("[車輛] 倒車警報:哔哔~");
}
// IConstructionVehicle 版本
void IConstructionVehicle.TurnOnBackUpSound()
{
Console.WriteLine("[工程車] 倒車警報:轟隆+哔哔~");
}
public void Accelerate() => Console.WriteLine("加速中...");
public void Stop() => Console.WriteLine("煞車停止");
public void ExecuteDump() => Console.WriteLine("貨箱傾卸中...");
}
var truck = new DumpTruck();
truck.Accelerate(); // 直接呼叫
// 需轉型至介面才能呼叫顯式實作
((IVehicle)truck).TurnOnBackUpSound(); // 輸出:[車輛] 倒車警報:哔哔~
((IConstructionVehicle)truck).TurnOnBackUpSound(); // 輸出:[工程車] 倒車警報:轟隆+哔哔~
顯式實作的方法不會出現在類別的公用介面中,僅能透過介面參考存取,優點:
interface IBackupSoundStrategy { void Play(); }
class VehicleBackupSound : IBackupSoundStrategy { public void Play() => Console.WriteLine("哔哔"); }
class ConstructionBackupSound : IBackupSoundStrategy { public void Play() => Console.WriteLine("轟隆+哔哔"); }
class SmartDumpTruck
{
private readonly IBackupSoundStrategy _sound;
public SmartDumpTruck(IBackupSoundStrategy sound) => _sound = sound;
public void TurnOnBackUpSound() => _sound.Play();
}
// 使用
var truck1 = new SmartDumpTruck(new VehicleBackupSound());
var truck2 = new SmartDumpTruck(new ConstructionBackupSound());
interface IVehicle
{
void Accelerate();
void Stop();
void TurnOnBackUpSound() => Console.WriteLine("預設車輛倒車音"); // 預設實作
}
interface IConstructionVehicle
{
void ExecuteDump();
void TurnOnBackUpSound() => Console.WriteLine("預設工程車倒車音");
}
class ModernDumpTruck : IVehicle, IConstructionVehicle
{
public void Accelerate() => Console.WriteLine("電動加速");
public void Stop() => Console.WriteLine("再生煞車");
public void ExecuteDump() => Console.WriteLine("液壓傾卸");
// 明確選擇或覆寫
void IVehicle.TurnOnBackUpSound() => IVehicle.DefaultTurnOnBackUpSound(); // 呼叫預設
}
| 情境 | 建議方案 | 關鍵字 |
|---|---|---|
| 單一繼承足夠 | 基底類別 + 虛擬方法 | abstract, virtual, override |
| 需組合多種獨立行為 | 多重介面實作 | interface, explicit implementation |
| 介面方法同名衝突 | 顯式介面實作 | InterfaceName.Method() |
| 行為需動態切換 | 策略模式 / 委派注入 | Func<T>, Strategy Pattern |
| 提供預設行為供選擇性覆寫 | 預設介面方法 (C# 8+) | default interface method |
C# 以「單一繼承 + 多重介面實作」取代 C++ 風格的多重繼承,配合顯式介面實作解決同名衝突,並提供實作隱藏降低耦合。現代 C# (8.0+) 更引入預設介面方法,讓介面演進不再破壞現有實作。掌握這些模式,即能設計出彈性、可維護的物件導向架構。