接口应用场景:
一、场景 1:定义契约(规范行为),实现 "约定优于配置"
这是接口最基础也最核心的作用:接口定义了一组 "必须实现的行为"(方法、属性、事件等),但不提供具体实现,相当于一份 "契约"。任何类实现这个接口,就必须遵守契约,实现接口中的所有成员。
适用场景
当你需要让多个不同的类都具备相同的行为,但每个类的实现方式不同时,用接口定义这份行为契约。
// 定义接口:契约是"具备打印功能"
public interface IPrintable
{
// 只定义方法签名,没有具体实现
void Print();
}
// 类1:文档类,实现"可打印"契约
public class Document : IPrintable
{
public string Content { get; set; }
// 实现接口的Print方法(文档的打印逻辑)
public void Print()
{
Console.WriteLine($"打印文档:{Content}");
}
}
// 类2:图片类,实现"可打印"契约
public class Image : IPrintable
{
public string ImagePath { get; set; }
// 实现接口的Print方法(图片的打印逻辑)
public void Print()
{
Console.WriteLine($"打印图片:{ImagePath}");
}
}
// 调用端:只依赖接口,不依赖具体类
public class PrintManager
{
// 方法参数是接口类型,接收任何实现了IPrintable的类
public void PrintItem(IPrintable printable)
{
printable.Print(); // 调用的是具体类的实现
}
}
// 测试代码
class Program
{
static void Main()
{
PrintManager manager = new PrintManager();
// 传入Document实例
manager.PrintItem(new Document { Content = "Hello World" });
// 传入Image实例
manager.PrintItem(new Image { ImagePath = "photo.jpg" });
}
}
二、场景 2:解决类的单继承限制,实现 "多继承式" 的行为复用
C# 中类只能单继承 (一个类只能有一个父类),但可以实现多个接口,这让类可以具备多个不同的行为维度,弥补了单继承的不足。
适用场景:
当一个类需要具备多种不同的行为(比如既可以打印,又可以序列化),而这些行为来自不同的 "维度" 时,用多个接口实现。
// 接口1:可打印
public interface IPrintable
{
void Print();
}
// 接口2:可序列化
public interface ISerializable
{
string Serialize();
}
// 类:同时实现两个接口,具备两种行为
public class User : IPrintable, ISerializable
{
public string Name { get; set; }
public int Age { get; set; }
// 实现IPrintable的Print方法
public void Print()
{
Console.WriteLine($"打印用户信息:{Name},{Age}岁");
}
// 实现ISerializable的Serialize方法
public string Serialize()
{
return $"{{\"Name\":\"{Name}\",\"Age\":{Age}}}";
}
}
// 测试代码
class Program
{
static void Main()
{
User user = new User { Name = "张三", Age = 20 };
user.Print(); // 调用打印行为
Console.WriteLine(user.Serialize()); // 调用序列化行为
}
}
三、场景 3:实现解耦,提升代码的可测试性和可维护性
在实际开发中(尤其是分层架构、依赖注入场景),接口是解耦的关键:上层代码依赖接口,下层代码实现接口,从而让上下层代码互不依赖具体实现,只依赖契约。
适用场景:
- 分层架构(如 UI 层依赖业务逻辑层的接口,而非具体的业务类)。
- 依赖注入(DI)和控制反转(IOC):比如ASP.NET Core 中的服务注入。
- 单元测试:用 mock 对象(如 Moq 框架)模拟接口的实现,测试上层代码。
// 第一步:定义业务接口(契约)
public interface IUserService
{
string GetUserName(int id);
}
// 第二步:实现接口(具体业务逻辑)
public class UserService : IUserService
{
// 模拟从数据库获取数据
public string GetUserName(int id)
{
return id == 1 ? "张三" : "未知用户";
}
}
// 第三步:上层代码(如UI层)依赖接口,不依赖具体实现
public class UserController
{
private readonly IUserService _userService;
// 构造函数注入接口实例
public UserController(IUserService userService)
{
_userService = userService;
}
public void ShowUserName(int id)
{
Console.WriteLine(_userService.GetUserName(id));
}
}
// 测试代码
class Program
{
static void Main()
{
// 1. 实际运行时:传入真实的UserService
IUserService realService = new UserService();
UserController controller = new UserController(realService);
controller.ShowUserName(1); // 输出:张三
// 2. 单元测试时:传入mock的IUserService(无需连接数据库)
// var mockService = new Mock<IUserService>();
// mockService.Setup(s => s.GetUserName(1)).Returns("测试用户");
// UserController testController = new UserController(mockService.Object);
// testController.ShowUserName(1); // 输出:测试用户
}
}
