接口是代码世界的“契约书”:它定义必须实现哪些功能,但不关心具体如何实现。如同USB标准规定尺寸和传输协议,而U盘厂商自由决定内部构造。
痛点场景:为什么需要接口?
原生代码局限(问题演示)
class CA { public string Name; public int Age; } // 类A
class CB { public string First, Last; public double PersonsAge; } // 类B
// 仅支持CA类型的打印方法
static void PrintInfo(CA item)
{
Console.WriteLine($"Name:{item.Name}, Age:{item.Age}");
}
核心矛盾:
- PrintInfo 方法强依赖CA的结构,无法处理CB对象
- 硬改参数类型会导致字段名不匹配(CB没有Name字段)
- 重复写逻辑相似的PrintInfoForCB方法违反代码复用原则
接口解决方案:定义统一契约
步骤拆解
// 1️⃣ 定义接口(功能清单)
interface IInfo
{
string GetName(); // 强制要求实现名称获取
string GetAge(); // 强制要求实现年龄获取
}
// 2️⃣ 类实现接口(签订契约)
class CA : IInfo
{
public string Name; public int Age;
public string GetName() => Name; // CA的实现方式
public string GetAge() => Age.ToString();
}
class CB : IInfo
{
public string First, Last; public double PersonsAge;
public string GetName() => $"{First} {Last}"; // CB的实现方式
public string GetAge() => PersonsAge.ToString("0.0");
}
// 3️⃣ 面向接口编程(解除具体依赖)
static void PrintInfo(IInfo item) // ✅ 关键转型:接收接口类型
{
Console.WriteLine($"Name:{item.GetName()}, Age:{item.GetAge()}");
}
运行效果
# 输入CA对象:Name:John Doe, Age:35
# 输入CB对象:Name:Jane Doe, Age:33.0
实战进阶:IComparable接口排序
未实现接口的陷阱
class MyClass { public int TheValue; }
MyClass[] arr = new MyClass[5];
Array.Sort(arr); // ❌ 运行时异常:不知如何比较对象
实现接口赋予排序能力
class MyClass : IComparable // 实现系统内置接口
{
public int TheValue;
// 必须实现的方法:定义对象比较规则
public int CompareTo(object obj)
{
MyClass other = (MyClass)obj;
return TheValue.CompareTo(other.TheValue); // 复用int的CompareTo
}
}
实现后效果
// 排序前:[20, 4, 16, 9, 2]
Array.Sort(arr);
// 排序后:[2, 4, 9, 16, 20] ✅
💡 核心价值总结(接口的三大意义)
特点 | 说明 | 案例体现 |
---|---|---|
解耦 | 分离功能定义与实现 | PrintInfo脱离具体类依赖 |
多态支持 | 同一方法处理不同类型 | 同时处理CA/CB对象 |
强制标准化 | 确保关键行为存在 | 排序必须实现CompareTo |
🚀 接口使用场景清单
- 跨类型统一操作(如示例中的打印/排序)
- 插件系统开发(主程序通过接口调用插件)
- 单元测试模拟(Mock对象实现接口替代真实服务)
- API设计契约(微服务间通过接口定义交互规范)
在.NET 5+中,接口更支持默认实现(如public void Log() => Console.Write(“Default”)),进一步平衡灵活性与强制性。
🌟 思维升华
接口的本质是制定行业标准:
如同充电接口统一让手机/电脑互通,
代码接口让不同类对象共享协作语言。
优秀的架构师设计接口,普通的程序员实现接口